آموزش Domain Driven Design (DDD) + EF Core (قسمت دوم)

توجه: این مقاله به مرور زمان، ویرایش و یا تکمیل می‌شود!تقاضا: در صورتی که با مشکل تایپی، دستوری و یا مفهومی در این مقاله برخورد کردید، از شما دوست عزیز و گرامی، صمیمانه تقاضا می‌کنم که اینجانب را مطلع کرده، تا نسبت به تصحیح و یا تکمیل آن، در اسرع وقت، اقدام نمایم.با کمال تشکرداریوش تصدیقیکانال تلگرام: IranianExperts@شماره تلفن همراه: ۰۹۱۲۱۰۸۷۴۶۱نشانی پست الکترونیکی: DariushT@GMail.comفیلم‌های آموزشی https://www.aparat.com/DariushTآدرس سایت‌ها: https://WebsiteAnalytics.ir - http://IranianExperts.ir - http://Date2Date.ir - https://DTApp.irنسخه مقاله: ۱.۲ - تاریخ بروزرسانی: ۱۴۰۰/۰۳/۰۲به طور کلی زمانی که می‌خواهیم یک Enum یا Enumeration مثلا برای جنیست ایجاد نماییم، به شکل ذیل عمل می‌کنیم:ولی زمانی که می‌خواهیم مفهموم Enum و یا Enumeration را در DDD‌ پیاده‌سازی نماییم، معمولا از یک class به جای enum استفاده می‌کنیم.تکنیک خلق یک کلاس Enumeration در DDDتصویر شماره یکبرای Enumeration ای که در مد نظر داریم (جنسیت)، در Class Library ای به نام Domain، اقدام به ایجاد کلاس (Gender) آن می‌کنیم.باید دقت داشته باشیم، در صورتی که این Enum مربوط به Entity, Aggregate Root, Value Object خاصی باشد، این کلاس را در کنار آن کلاس و در داخل همان پوشه مربوطه ایجاد می‌کنیم، ولی در صورتی‌که احساس کنیم و یا اطمینان داشته باشیم که Enum مورد نظر در Entity, Aggregate Root, Value Object دیگری نیز مورد استفاده قرار می‌گیرد، آن‌را در داخل پوشه‌ای به نام SharedKernel ایجاد می‌کنیم.در مثال فوق نیز چون اطمینان داریم که این کلاس (Gender) در کلاس‌های دیگر DDD‌ نیز مورد استفاده قرار می‌گیرد، آن‌را دار داخل پوشه SharedKernel ایجاد می‌کنیم.در پوشه SeedWork، کلاس‌ها و اینترفیس‌هایی ایجاد شده‌اند که در تولید پروژه‌های DDD‌ بسیار اهمیت دارند که پس از اتمام این مجموعه مقالات در مورد کدهای درج شده در آن‌ها نیز توضیحات کاملی خواهیم داد. فعلا با محتوای این کلاس‌ها و اینترفیس‌ها کاری نداریم و صرفا از آن‌ها در مکان‌هایی که نیاز داریم، استفاده می‌کنیم. در این مثال ما به کلاسی به نام Enumeration نیاز داریم و به همین جهت، کلاس Gender را از آن Inherit کرده‌ایم.به هر حال EF (کماکان) محدودیت‌هایی دارد و باید در طراحی خود نکاتی را رعایت نماییم! برای این منظور Default Constructor کلاس Gender را نوشته و Access Modifier آن‌را protected تعریف می‌کنیم.یک Constructor دیگر می‌نویسیم که در زمان خلق شیء، مقدار Id و Name‌ را به آن Pass کنیم. Access Modifier این Constructor را نیز به صورت protected تعریف می‌کنیم. بدیهی است که با این عمل، به هیچ عنوان نمی‌توان از دنیای بیرون این کلاس، شیء ایجاد کرد!حال به تعداد مقادیر Enum ای که مورد نظر است (در این مثال خانم و آقا)، فیلدهایی به صورت public, static, readonly در داخل کلاس مربوطه ایجاد می‌کنیم (خط ۵ و ۶).معمولا در پروژه‌های خود یک Solution Folder به نام Resources ایجاد می‌کنیم و در داخل آن نیز یک Class Library به نام Resources ایجاد می‌کنیم و در داخل آن یک Resource File به نام Data Dictionary ایجاد می‌کنیم:تصویر شماره دو و تمام عناوین خود را در داخل آن قرار می‌دهیم.تصویر شماره سهنکته:‌ باید دقت داشته باشیم که Access Modifier این Resource File‌ را در حالت Public قرار دهیم.نکته: باید Reference ای از Class Library مذکور (Resources) در داخل Domain Class Library ایجاد نماییم.همانگونه که در تصویر شماره یک و در خطوط ۵ و ۶ ملاحظه می‌کنیم. برای عناوین دو Enum، از Resource File استفاده کرده‌ایم و به صورت Hard Code، عناوین را ننوشته‌ایم!در پروژه‌های DDD، معمولا یک Solution Folder به نام Infrastructure ایجاد کرده و در داخل آن یک Class Library به نام Persistence ایجاد می‌کنیم.نکته: در پروژه‌های قدیم، به جای نام Persistence، از نام‌هایی مانند DAL, Dal, DataAccess, Data استفاده می‌شده است!از آن‌جایی که قرار است کلاس Gender، تبدیل به یک جدول در بانک‌اطلاعاتی گردد، باید برای آن Configuration نوشته شود. هر چند که می‌توان این Configuration ها را در داخل تابع OnConfiguring کلاس DatabaseContext نوشت، ولی معمولا عرف بر آن است که برای هر کلاسی که می‌خواهیم تبدیل به یک جدول بانک‌اطلاعاتی شود، یک کلاس Configuration جداگانه‌ای ایجاد نماییم و سپس در تابع OnConfiguring از آن استفاده نماییم.برای این منظور در Persistence Class Library پوشه‌ای به نام SharedKernel (متناظر آن‌چه که در Domain Class Library انجام داده‌ایم) ایجاد کرده و در داخل آن کلاسی به نام GenderConfiguration ایجاد می‌کنیم:محتوای کلاس GenderConfiguration‌ را به شکل ذیل تکمیل می‌کنیم:به طور کلی، کلاس‌های Configuration‌ باید به صورت internal تعریف شوند (خط ۵)کلاس‌های Configuration باید از اینترفیسی به نام IEntityTypeConfiguration ارث‌بری نمایند (خط ۶)نوشتن Default Constructor الزامی است و صرفا به این دلیل نوشته شده است که ما اصلی داریم با این مضمون که هر آن‌چه ما ننویسیم، Compiler‌ به طور اتوماتیک می‌نویسد و یا برداشت می‌کند را به عنوان یک حرفه‌ای باید بنویسیم! (خط ۸)زمانی که کلاس مربوطه از اینتفریسی به نام IEntityTypeConfiguration‌ اصطلاحا Inherit می‌شود، باید تابعی به نام Configure را پیاده‌سازی نماییم (خط ۱۲)در مثال فوق، اگر بخواهیم نام دلخواهی را برای جدول بانک‌اطلاعاتی انتخاب نماییم، باید از تابعی به نام ToTable استفاده کنیم (خط ۱۷). باید دقت داشته باشیم که این تابع یک Extension Method می‌باشد و در صورتی می‌توانیم آن‌را مشاهده کرده و استفاده نماییم که از دستور ذیل در ابتدای فایل استفاده کنیم:using Microsoft.EntityFrameworkCore;در نسخه‌های اولیه EF، زمانی که EF تصمیم می‌گرفت که جدولی در بانک‌اطلاعاتی ایجاد نماید، به طور خودکار نام کلاس را به صورت اسم جمع به عنوان نام جدول در نظر می‌گرفت. در نسخه‌های جدید EF Core، صرفا همان نام کلاس را برای جدول در نظر می‌گیرد! لذا باید توجه داشته باشیم که اگر خط ۱۷ را Comment نماییم، نام جدول در بانک‌اطلاعاتی Gender خواهد بود و نه Genders!در خط ۲۱ و با استفاده از تابع HasKey می‌توانیم اعلام کنیم که چه فیلد و یا Property به عنوان Primary Key جدول در نظر گرفته شود. باید دقت داشته باشیم که نوشتن این دستور نیز الزامی نیست، چرا که EF‌ در صورتی که فیلد و یا Property‌ هایی به نام‌های Id, ID, GenderId, GenderID مشاهده نماید، آن را به عنوان Primary Key‌ در نظر می‌گیرد.و اما ادامه این فایل:در خط ۲۶ اعلام می‌کنیم که نمی‌خواهیم بانک‌اطلاعاتی در زمان درج رکورد (Record) یک عدد به Id‌ اصطلاحا Assign کند و ما خودمان می‌خواهیم در زمان خلق یک شیء مقدار Id را مشخص کنیم.به طور خودکار، فیلدها و Property هایی که از جنس string می‌باشند، در بانک‌اطلاعاتی به صورت Allow Null بوده و از جنس nvarchar(max) تعریف می‌شوند. در خط ۳۲، اعلام می‌کنیم که فیلد Name نمی‌خواهیم Allow Null‌ بوده و می‌خواهیم که الزامی (Required) باشد. در خط ۳۳، اعلام می‌کنیم که فیلد Name نمی‌خواهیم از جنس nvarchar(max)‌ بوده و می‌خواهیم به صورت nvarchar(10) تعریف شود.Data Seedingنکته بسیار مهم: برای کلاس‌های Enumeration مانند Gender، باید رکوردهای آن را به صورت Seed (حتما) تعریف کنیم! برای این منظور با استفاده از دستورات خطوط ۳۹ و ۴۰، رکوردهای مورد نظر خود را در بانک‌اطلاعاتی درج می‌کنیم!پایان