خواندنیهای 2 مرداد
اس کیوال سرور
الگوهای طراحی برنامه نویسی شیءگرا
امنیت
توسعه وب
دات نت فریم ورک
دبلیو اف
سی و مشتقات
کتابهای رایگان
لینوکس
متفرقه
محیطهای مجتمع توسعه
مسایل انسانی، اجتماعی و مدیریتی برنامه نویسی
ویندوز
مفهوم عملگر شیفت در #C
عملگر شیفت به سمت راست و یا <<، عددی را به تعداد بیت مشخص شده (x >> count)، به سمت راست منتقل میکند و دو نوع دارد:
الف) شیفت به راست منطقی
برای مثال اگر عدد 12 را به صورت باینری نمایش دهیم، به صورت زیر خواهد بود:
00000000 00000000 00000000 00001100
00000000 00000000 00000000 00000110
در این حالت همواره فرض میشود که عدد مدنظر، unsigned است.
ب) شیفت به راست ریاضی
شیفت به راست ریاضی، دقیقا مانند شیفت به راست منطقی است؛ مانند مثال زیر که عدد 1001 باینری را دو بیت به سمت راست منتقل میکند:
uint e = 0b_1001; Console.WriteLine($"Before: {Convert.ToString(e, toBase: 2),4}"); // Before: 1001 uint f = e >> 2; Console.WriteLine($"After: {Convert.ToString(f, toBase: 2).PadLeft(4, '0'),4}"); // After: 0010
برای مثال نمایش باینری عدد منفی 2,147,483,552- به صورت زیر است:
10000000 00000000 00000000 01100000
11111000 00000000 00000000 00000110
int x = -8; Console.WriteLine($"Before: {x,11}, hex: {x,8:x}, binary: {Convert.ToString(x, toBase: 2),32}"); // Before: -8, hex: fffffff8, binary: 11111111111111111111111111111000 int y = x >> 2; Console.WriteLine($"After >>: {y,11}, hex: {y,8:x}, binary: {Convert.ToString(y, toBase: 2),32}"); // After >>: -2, hex: fffffffe, binary: 11111111111111111111111111111110 int z = x >>> 2; Console.WriteLine($"After >>>: {z,11}, hex: {z,8:x}, binary: {Convert.ToString(z, toBase: 2).PadLeft(32, '0'),32}"); // After >>>: 1073741822, hex: 3ffffffe, binary: 00111111111111111111111111111110
سؤال: در زبان جاوا، عملگر <<< به معنای unsigned right shift است؛ اما چنین عملگری در زبان #C تا نگارش 11 آن وجود ندارد؛ چرا؟!
تا پیش از C# 11 اگر نیاز به کار بر روی signed types جهت رسیدن به نتیجهی عملگر <<< وجود داشته باشد (انجام شیفت منطقی؛ یعنی صرفنظر کردن از نوع علامت عدد)، میتوان از متدهای الحاقی زیر استفاده کرد که ابتدا آنها را به نمونههای unsigned تبدیل میکند و کار شیفت را انجام میدهد و سپس نوع اصلی را بازیابی میکند:
public static int UnsignedRightShift(this int signed, int places) { unchecked { var unsigned = (uint)signed; unsigned >>= places; return (int)unsigned; } } public static long UnsignedRightShift(this long signed, int places) { unchecked { var unsigned = (ulong)signed; unsigned >>= places; return (long)unsigned; } }
مشکل مهم این روش عدم سازگاری کامل آن با EF است. برای مثال در آن تفاوتی بین (Include(x=>x.Tags و (Include(x=>x.Users وجود ندارد. به همین جهت در این نوع موارد، قادر به تولید کلید منحصربفردی جهت کش کردن اطلاعات یک کوئری مشخص نیست. در اینجا یک کوئری LINQ، به معادل رشتهای آن تبدیل میشود و سپس Hash آن محاسبه میگردد. این هش، کلید ذخیره سازی اطلاعات حاصل از کوئری، در سیستم کش خواهد بود. زمانیکه دو کوئری Include دار متفاوت EF، هشهای یکسانی را تولید کنند، عملا این سیستم کش، کارآیی خودش را از دست میدهد. برای رفع این مشکل پروژهی دیگری به نام EF cache ارائه شدهاست. این پروژه بسیار عالی طراحی شده و میتواند جهت ایده دادن به تیم EF نیز بکار رود. اما در آن فرض بر این است که شما میخواهید کل سیستم را در یک کش قرار دهید. وارد مکانیزم DBCommand و DataReader میشود و در آنجا کار کش کردن تمام کوئریها را انجام میدهد؛ مگر آنکه به آن اعلام کنید از کوئریهای خاصی صرفنظر کند.
با توجه به این مشکلات، روش بهتری برای تولید هش یک کوئری LINQ to Entities بر اساس کوئری واقعی SQL تولید شده توسط EF، پیش از ارسال آن به بانک اطلاعاتی به صورت زیر وجود دارد:
private static ObjectQuery TryGetObjectQuery<T>(IQueryable<T> source) { var dbQuery = source as DbQuery<T>; if (dbQuery != null) { const BindingFlags privateFieldFlags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public; var internalQuery = source.GetType().GetProperty("InternalQuery", privateFieldFlags) .GetValue(source); return (ObjectQuery)internalQuery.GetType().GetProperty("ObjectQuery", privateFieldFlags) .GetValue(internalQuery); } return null; }
این اطلاعات، پایهی تهیهی کتابخانهی جدیدی به نام EFSecondLevelCache گردید. برای نصب آن کافی است دستور ذیل را در کنسول پاورشل نیوگت صادر کنید:
PM> Install-Package EFSecondLevelCache
var products = context.Products.Include(x => x.Tags).FirstOrDefault();
var products = context.Products.Include(x => x.Tags).Cacheable().FirstOrDefault(); // Async methods are supported too.
پس از آن نیاز است کدهای کلاس Context خود را نیز به نحو ذیل ویرایش کنید (به روز رسانی شدهی آن در اینجا):
namespace EFSecondLevelCache.TestDataLayer.DataLayer { public class SampleContext : DbContext { // public DbSet<Product> Products { get; set; } public SampleContext() : base("connectionString1") { } public override int SaveChanges() { return SaveAllChanges(invalidateCacheDependencies: true); } public int SaveAllChanges(bool invalidateCacheDependencies = true) { var changedEntityNames = getChangedEntityNames(); var result = base.SaveChanges(); if (invalidateCacheDependencies) { new EFCacheServiceProvider().InvalidateCacheDependencies(changedEntityNames); } return result; } private string[] getChangedEntityNames() { return this.ChangeTracker.Entries() .Where(x => x.State == EntityState.Added || x.State == EntityState.Modified || x.State == EntityState.Deleted) .Select(x => ObjectContext.GetObjectType(x.Entity.GetType()).FullName) .Distinct() .ToArray(); } } }
کدهای کامل این پروژه را از مخزن کد ذیل میتوانید دریافت کنید:
EFSecondLevelCache
پ.ن.
این کتابخانه هم اکنون در سایت جاری در حال استفاده است.
کاربرد Mixins در Vue.js
npm install vue-class-component vue-property-decorator --save-dev
<template> <div> <p>Long-form v-model example</p> <input :value="myDataProperty" @input="updateMyProperty($event)"/> </div> </template> <script> import Vue from 'vue' import { Component } from 'vue-property-decorator' @Component export default class App extends Vue { // Data property myDataProperty: string; // Lifecycle hook mounted () { this.myDataProperty = 'Boop' } // Component method updateMyProperty ($event) { this.myDataProperty = $event.target.value } } </script>
@Component({ name: 'App', components: { AppModal } })
@Prop @PropSync @Provide @Model @Watch @Inject @Provide @Emit
import { Vue, Component, Prop } from 'vue-property-decorator' @Component export default class YourComponent extends Vue { @Prop(Number) readonly propA: number | undefined @Prop({ default: 'default value' }) readonly propB!: string @Prop([String, Boolean]) readonly propC: string | boolean | undefined }
export default { props: { propA: { type: Number }, propB: { default: 'default value' }, propC: { type: [String, Boolean] } } }
مطابق با ویکی پدیا، سطوح
دسترسی مشخص میکند که کدام کاربران یا سیستم پردازش اجازه دسترسی به اشیاء را
دارند(Authentication)، همچنین چه عملیاتهایی بر روی اشیاء
مجازند که اجرا شوند(Authorization).
در مورد جوملا، ما دو جنبه جدا برای سطوح دسترسی
داریم:
1.
کدام کاربران به چه بخشهایی میتوانند دسترسی
داشته باشند؟ برای مثال، انتخاب یک منو برای کدام کاربر فعال خواهد بود؟
2.
چه عملیات (یا اقداماتی) کاربر میتواند بر روی اشیاء
داشته باشد؟ برای مثال، آیا کاربر میتواند یک مطلب را ارسال یا ویرایش کند؟
ماهیتهای موجود در سیستم :
·
کاربران
کاربر
میتواند به گروههای مختلفی اختصاص یابد.
·
گروهها کاربری
شامل
مجوزهایی به صورت پیش فرض میباشند که این مجوزها را از سطوح بالایی نیز به ارث میبرند.
·
سطوح دسترسی
شامل
یک یا چند گروه کاربری میباشد و سطوح دسترسی به محتواهای سایت نسبت داده میشود
یعنی اگر یک مطلب دارای سطح دسترسی عمومی باشد آنگاه تمامی گروههای کاربری
که در عمومی وجود دارند میتوانند مطلب را مشاهده کنند.
·
عملیات و مجوزها
به
صورت پیش فرض یک سری عملیات در سیستم تعریف شده است شامل ویرایش ، حذف و غیره که
برای هر گروه کاربری (تعدادی گروه کاربری به صورت پیش فرض در سیستم تعریف شده است)
به صورت پیش فرض مجوزهایی در نظر گرفته شده است که این مجوزها قابلیت ارث بری از
والد گروه به فرزند رانیز دارا میباشد پس با این حساب همیشه در جوملا والد از سطح
دسترسی پایینتری نسبت به فرزند برخوردار میباشد.
اما
باید گفت در جوملا به ازای هر
کامپوننت نیز میتوان این مجوزها را به ازای گروههای مختلف تغییر داد در این جا
هم هر کامپوننت دارای مجوزهای پیش فرضی میباشد که در هنگام نصب کامپوننت برای
آن در نظر گرفته میشود.
جداول این سیستم :
: users جدول کاربران
usergroups : جدول گروههای کاری یا همان نقشهای کاربری
user_usergroup_map : جدول واسط بین کاربران و گروههای کاری به منظور ایجاد
رابطهی چند به چند (n:n)
assets : این جدول که از جوملا 1.6 به بعد به دیتابیس جوملا افزوده
شده است مهمترین جدول در این سیستم میباشد . که در آن به ازای هر جز که سطح
دسترسی باید برای آن لحاظ گردد یک سطر در نظر گرفته میشود که این سطر باتوجه به
افزایش اجزا سیستم تغییر و به صورت داینامیک به جدول اضافه میگردد ضمنا این سطور
قابلیت ارث بری از یکدیگر را نیز دارا میباشند. در هر بک از سطرها فیلدی به نام rulsوجود دارد محتوای این فیلد از نوع داده ای json میباشد با یک
مثال شاید بهتر بتوان توضیح داد :
محتوای
فیلد کامپوننت بنر :
{"core.admin":{"9":1,"7":1},"core.manage":{"6":1},"core.create":[],"core.delete":[],"core.edit}
در این جا “core.admin” مجوز دسترسی مدیریتی به این کامپوننت میباشد که
گروههای کاری شماره 7 و 9 دارای چنین دسترسی میباشند . ضمنا عملیاتهای "core.create" از سطوح
بالاتر یا همان سطر والد خود ارث بری میکند.
Viewlevel : در این جدول سطوح دسترسی تعریف شده اند مهمترین فیلد این
جدول نیز rulsنام دارد و حاوی id گروه
هایی است که به این سطح دسترسی ، دسترسی دارند.
به طور مثال سطح دسترسی ثبت نام شده حاوی [6,2,8] میباشد یعنی گروههای کاری با idهای مورد نظر میتوانند به محتواهای با سطح دسترسی ثبت نام شده دسترسی داشته باشند.
دیاگرام جداول :
افزونهی زیر کار مشخص کردن کلماتی که قابل تبدیل از فارسی به پارسی هستند را انجام میدهد (به صورت خودکار و در زمان تایپ) و همچنین امکان تبدیل خودکار آنها را نیز فراهم میکند.
برای نصب آن باید به ترتیب زیر عمل کنید (مهم)
- نصب دات نت فریم ورک 3 و نیم (نزدیک به 231 مگابایت)
اگر VS.Net 2008 SP1 را دارید نیازی به این بسته نخواهید داشت.
- نصب بسته به روز رسانی سیستم (حدودا 14 مگ)
- نصب افزونه (حدودا 550 کیلوبایت)
لطفا این سه مرحله را به ترتیب انجام دهید در غیر اینصورت نتیجه نخواهید گرفت.
همچنین بدیهی است که برنامه باید با دسترسی admin نصب شود.
و همانطور که در عنوان این موضوع نیز ذکر گردید، این افزونه تنها برای MS-Word 2007 طراحی شده است.
سورس کامل و جزئیات نحوهی برنامه نویسی آنرا در طی روزهای آینده در این بلاگ مشاهده خواهید کرد.
پس از نصب به گزینهی word options مراجعه کنید: (جهت اطمینان از نصب آن)
این افزونه را باید در لیست مربوطه مشاهده نمائید:
1) مطلب شما نیاز به مقدمه دارد
نیاز به مقدمه داشتن به معنای نوشتن کلمه «مقدمه» در ابتدای یک متن نیست. به این معنا است که به خواننده بگوئید مشکل کجا بوده یا به چه دلیلی قصد دارید مطلب جاری را منتشر کنید. بنابراین جهت تهیه یک مطلب خوب، یک راست اصل مطلب را شروع نکنید. لازم است چند سطری در مورد علت انتشار آن توضیح دهید.
2) پیش از انتشار مطلب چندبار آنرا مطالعه کنید
یک مطلب خوب نیاز به جمله بندی مناسب، استفاده از نقطه، ویرگول و امثال آن دارد و بدون استفاده از آنها متن شما هرچقدر هم حرفهای باشد، خواندنش مشکل خواهد بود و جلوه مناسبی نخواهد داشت.
3) سعی کنید در عنوان مطلب خود از کلمات کلیدی استفاده کنید
استفاده از کلمات کلیدی در عنوان مطالب، جستجوی آنها را برای خواننده سادهتر کرده و همچنین کمک بزرگی است به موتورهای جستجو در یافتن نتایجی بهتر.
4) تکرار کلمات و جملات یکسان را در متن خود به حداقل برسانید
برای مثال مدام در متن خود جمله «همانطور که ملاحظه میکنید» را تکرار نکنید. استفاده از افعال تکراری و جملات تکراری در یک متن باید حداقل باشند. برای نمونه اگر جمله جاری به «میشود» ختم خواهد شد، جمله بعدی را به «میگردد» ختم کنید. اگر جملهای دارای کلمات «برای مثال» است، جمله بعدی بهتر است به همراه کلمات «برای نمونه» باشد.
5) از جملات طولانی استفاده نکنید
یک جمله باید حداکثر یک سطر یا یک سطر و نصفی طول داشته باشد و گرنه خواننده را به شدت در دنبال کردن آن به زحمت خواهید انداخت. جملات طولانی را به جملاتی کوتاهتر خرد کنید.
6) استفاده از علامت تعجب را به حداقل برسانید
اشخاصی که مدام از چندین علامت تعجب پشت سرهم استفاده میکنند یا مدام از علامت سؤال به همراه چندین علامت تعجب بهره میگیرند، حس مسخره کردن شخص مقابل و همچنین عدم تعادل روانی خود را القاء میکنند.
7) در متن خود از تصاویر استفاده کنید
انسان موجودی است بصری. قدرت یادگیری ما از طریق دیدن چند برابر زمانی است که از طریق شنیدن یا خواندن نسبت به فراگیری مطلبی اقدام میکنیم.
« ما ...
10 درصد چیزهایی را که میخوانیم
20 درصد چیزهایی را که میشنویم
30 درصد چیزهایی را که میبینیم
50 درصد چیزهایی را که میبینیم و میشنویم
70 درصد چیزهایی را که در موردشان بحث میکنیم
80 درصد چیزهایی را که تجربه میکنیم
95 درصد چیزهایی را که به دیگران میآموزیم
... یاد میگیریم
»
8) اگر در سایتی مطلب مینویسید، اهداف کلی آنرا حفظ کنید
اگر نام سایت شما برنامه نویسی است، خواننده به دنبال شعر، داستان و یا مطالب خیلی شخصی و خصوصی شما نمیگردد. سایتهای زیادی هستند که به این مقولهها میپردازند و خیلی زود سطح کاری خود را به این ترتیب به حداقل تنزل خواهید داد.
9) به صفحات داخلی سایت خود لینک دهید
در مطلب تهیه شده سعی کنید به مطالب مشابه داخلی سایت خود لینک دهید. احتمال کپی شدن مطالب شما بسیار زیاد است. به این ترتیب میتوانید خوانندهها را در لابلای متن خود به مرجع اصلی هدایت کنید.
10) دست به اختراع برچسبهای جدید، پراکنده و بیهوده نزنید
اگر گروه بندی مطالب یک سایت بر اساس برچسبها است و تاکنون برچسبهای متعددی تعریف شده است، بهتر است از همانها استفاده کنید تا اینکه دست به اختراع زده و یک برچسب کاملا جدید را ثبت کنید. برای مثال اگر مطلب شما در مورد Entity framework است و تا کنون 20 مطلب ذیل این گروه ثبت شده، اختراع برچسب جدید EF Code first نه تنها کمکی نخواهد کرد، بلکه خوانندهای را که به دنبال یافتن مطالب یک گروه خاص است، سر در گم میکند. یا اگر قصد دارید یک برچسب کاملا جدید را اضافه کنید، حتما از یک برچسب کلی موجود نیز استفاده کنید تا روابط بین مطالب حفظ شوند.
11) مطالب شما بهتر است یک قسمت نتیجه گیری نیز داشته باشد
بهتر است در پایان یک مطلب، خلاصه بحث، پیشنهادها یا حتی سؤالاتی را مطرح کنید تا بتوانید خواننده را تا حدودی وادار به عکس العمل نمائید.
12) تا حد امکان از منابع سایت خود استفاده کنید
اگر قرار است تصویری در متن قرار گیرد، اگر نیاز است فایلی در سایت مطرح شود، بهتر است این موارد در سایت جاری هاست شوند؛ تا اینکه تصویر یک سایت دیگر را مستقیما در سایت خود لینک کنیم.
13) معرفی منابع
نیازی نیست در یک سایت، همانند مقالات علمی، در انتهای مطلب لیست منابع را ذکر نمود. در اینجا میشود قسمتی از جملات را به منبع استفاده شده لینک کرد. به این ترتیب دقیقا مشخص میشود هر قسمت و هر جملهای از چه ماخذی استفاده کرده و پیگیری آن سادهتر میشود.
14) تصاویر ارائه شده را فشرده کنید
فرمت مناسب ارائه تصویر در یک سایت bmp نیست. بهترین فرمت برای سایتها png است؛ از لحاظ حفظ تعداد رنگ و همچنین کاهش حجم. به علاوه ابزارهای زیادی برای کاهش حجم فایلهای png با حداقل افت کیفیت وجود دارند.
15) در مورد کدهای خود توضیح دهید
این مورد خصوصا به سایتهای برنامه نویسی مرتبط میشود. اینکه چند سطر کد بدون توضیح را در یک مطلب قرار دادهاید، نه لطفی است و نه اهمیتی دارد! هزاران هزار سطر از این دست کدها در GitHub، CodPlex و sourceforge وجود دارند. فرق کار شما با آنها در چیست؟
باید یک قسمت «توضیحات» ذیل کدهای ارائه شده وجود داشته باشد. همان نکاتی را که حین تهیه کدها در ذهن داشتید باید بتوانید توضیح دهید و گرنه ... کار شما ارزشی نخواهد داشت.
16) مطالب تجربی شما باید قابلیت تولید مجدد داشته باشند
برای مثال امروز در حین کار به یک مطلب جدید برخوردهاید که قصد دارید آنرا به اشتراک بگذارید. ذکر این نکته جدید به تنهایی کافی نیست. باید ابتدا بتوانید ذهن خواننده را جهت رسیدن به وضعیتی که قرار داشتید، آماده کنید. اگر قصد دارید قطعه کدی را به اشتراک بگذارید، خواننده باید بتواند این قطعه از پازل را در کنار قطعات دیگری که برای او ترسیم خواهید کرد، جای دهد. یا حداقل بتواند قطعه کد شما را بدون خطا کامپایل کند.
17) یک راست به سراغ کدنویسی و اصل مطلب نروید
اگر قرار است در مورد یک فناوری جدید در طی چند جلسه بحث کنید، لازم است یک جلسه کامل در مورد «چرا به این فناوری نیاز داریم» توضیح دهید. بنابراین ذکر اینکه بدون مقدمه به سراغ کدنویسی میرویم، سؤالات بسیاری را به جا خواهند گذاشت مانند ... «مشکل روشهای قبلی چی هست؟» «مزیت این روش جدید در کجاست؟» و تا نتوانید این مسایل را شرح دهید، کار شما خریدار نخواهد داشت.
18) در زبان فارسی نیم فاصلهها را رعایت کنید
در نگارش زبان فارسی فرق است بین «آمده ام» و «آمدهام» و یا «می شود» را باید «میشود» نوشت. میشود اندکی وقت گذاشت و با مبحث نیم فاصله آشنا شد .
در کل کار کردن در یک محیط گروهی و چند نویسندهای، به مرور زمان تجربههایی را به همراه خواهند داشت که با به اشتراک گذاشتن آنها و یا طرح صریح آنها، میتوان از تکرار اشتباهات متداول جلوگیری کرد.
public AddUserStatus Add(User user) { if (ExistsByEmail(user.Email)) return AddUserStatus.EmailExist; if (ExistsByUserName(user.UserName)) return AddUserStatus.UserNameExist; _users.Add(user); return AddUserStatus.AddingUserSuccessfully; }
using System.Linq; using System.Web.Mvc; using Iris.Datalayer.Context; namespace Iris.Web.Controllers { public class MigrationController : Controller { public ActionResult RemoveDuplicateUsers() { var db = new IrisDbContext(); var lstDuplicateUserGroup = db.Users .GroupBy(u => u.UserName) .Where(g => g.Count() > 1) .ToList(); foreach (var duplicateUserGroup in lstDuplicateUserGroup) { foreach (var user in duplicateUserGroup.Skip(1).Where(user => user.UserMetaData != null)) { db.UserMetaDatas.Remove(user.UserMetaData); } db.Users.RemoveRange(duplicateUserGroup.Skip(1)); } db.SaveChanges(); return new EmptyResult(); } } }
مقایسه ساختار جداول دیتابیس کاربران IRIS با ASP.NET Identity
ساختار جداول ASP.NET Identity به شکل زیر است:
ساختار جداول سیستم کنونی هم بدین شکل است:
همان طور که مشخص است در هر دو سیستم، بین ساختار جداول و رابطهی بین آنها شباهتها و تفاوت هایی وجود دارد. سیستم Identity دو جدول بیشتر از IRIS دارد و برای جداولی که در سیستم کنونی وجود ندارند نیاز به انجام کاری نیست و به هنگام پیاده سازی Identity، این جداول به صورت خودکار به دیتابیس اضافه خواهند شد.
دو جدول مشترک در این دو سیستم، جداول Users و Roles هستندکه نحوهی ارتباطشان با یکدیگر متفاوت است. در Iris بین User و Role رابطهی یک به چند وجود دارد ولی در Identity، رابطهی بین این دو جدول چند به چند است و جدول واسط بین آنها نیز UserRoles نام دارد.
از آن جایی که من قصد دارم در سیستم جدید هم رابطهی بین کاربر و نقش چند به چند باشد، به پیش فرضهای Identity کاری ندارم. به رابطهی کنونی یک به چند کاربر و نقشش نیز دست نمیگذارم تا در انتها با یک کوئری از دیتابیس، اطلاعات نقشهای کاربران را به جدول جدیدش منتقل کنم.
جدولی که در هر دو سیستم مشترک است و هستهی آنها را تشکیل میدهد، جدول Users است. اگر دقت کنید میبینید که این جدول در هر دو سیستم، دارای یک سری فیلد مشترک است که دقیقا هم نام هستند مثل Id، UserName و Email؛ پس این فیلدها از نظر کاربرد در هر دو سیستم یکسان هستند و مشکلی ایجاد نمیکنند.
یک سری فیلد هم در جدول User در سیستم IRIS هست که در Identity نیست و بلعکس. با این فیلدها نیز کاری نداریم چون در هر دو سیستم کار مخصوص به خود را انجام میدهند و تداخلی در کار یکدیگر ایجاد نمیکنند.
اما فیلدی که برای ذخیره سازی پسورد در هر دو سیستم استفاده میشود دارای نامهای متفاوتی است. در Iris این فیلد Password نام دارد و در Identity نامش PasswordHash است.
برای اینکه در سیستم کنونی، نام فیلد Password جدول User را به PasswordHash تغییر دهیم قدمهای زیر را بر میداریم:
وارد پروژهی DomainClasses شده و کلاس User را باز کنید. سپس نام خاصیت Password را به PasswordHash تغییر دهید. پس از این تغییر بلافاصله یک گزینه زیر آن نمایان میشود که میخواهد در تمام جاهایی که از این نام استفاده شده است را به نام جدید تغییر دهد؛ آن را انتخاب کرده تا همه جا Password به PasswordHash تغییر کند.
برای این که این تغییر نام بر روی دیتابیس نیز اعمال شود باید از Migration استفاده کرد. در اینجا من از مهاجرت دستی که بر اساس کد هست استفاده میکنم تا هم بتوانم کدهای مهاجرت را پیش از اعمال بررسی و هم تاریخچهای از تغییرات را ثبت کنم.
برای این کار، Package Manager Console را باز کرده و از نوار بالایی آن، پروژه پیش فرض را بر روی DataLayer قرار دهید. سپس در کنسول، دستور زیر را وارد کنید:
Add-Migration Rename_PasswordToPasswordHash_User
اگر وارد پوشه Migrations پروژه DataLayer خود شوید، باید کلاسی با نامی شبیه به 201510090808056_Rename_PasswordToPasswordHash_User ببینید. اگر آن را باز کنید کدهای زیر را خواهید دید:
public partial class Rename_PasswordToPasswordHash_User : DbMigration { public override void Up() { AddColumn("dbo.Users", "PasswordHash", c => c.String(nullable: false, maxLength: 200)); DropColumn("dbo.Users", "Password"); } public override void Down() { AddColumn("dbo.Users", "Password", c => c.String(nullable: false, maxLength: 200)); DropColumn("dbo.Users", "PasswordHash"); } }
بدیهی هست که این کدها عمل حذف ستون Password را انجام میدهند که سبب از دست رفتن اطلاعات میشود. کدهای فوق را به شکل زیر ویرایش کنید تا تنها سبب تغییر نام ستون Password به PasswordHash شود.
public partial class Rename_PasswordToPasswordHash_User : DbMigration { public override void Up() { RenameColumn("dbo.Users", "Password", "PasswordHash"); } public override void Down() { RenameColumn("dbo.Users", "PasswordHash", "Password"); } }
سپس باز در کنسول دستور Update-Database را وارد کنید تا تغییرات بر روی دیتابیس اعمال شود.
دلیل اینکه این قسمت را مفصل بیان کردم این بود که میخواستم در مهاجرت از سیستم اعتبارسنجی خودتان به ASP.NET Identity دید بهتری داشته باشید.
تا به این جای کار فقط پایگاه داده سیستم کنونی را برای مهاجرت آماده کردیم و هنوز ASP.NET Identity را وارد پروژه نکردیم. در بخشهای بعدی Identity را نصب کرده و تغییرات لازم را هم انجام میدهیم.