یکی از اتفاقات کسل کننده در نوشتن برنامه های که در اونها از Entity Framework استفاده میکنیم ثبت کردن تک به تک انتیتی ها یا همون مدل هامون توی فایل DbContext هست. این مساله زمانی بیشتر خسته کننده میشه که تعداد این مدل ها زیاد بشه. تصورش رو بکنید که اگر توی برنامه تون بالای 30 تا مدل داشته باشید چقدر تعداد کدهای فایل تون زیاد میشه و ممکنه خوانایی کدهاتون رو بیاره پایین.
در حالت عادی وقتی ما میخوایم مدل هامون رو توی DbContext تعریف کنیم، به ازای هر کدوم از اون مدل ها یک DbSet می سازیم. و فایل DbContext ما تقریبا یه چنین چیزی میشه:
public class DataContext : DbContext { public DataContext(DbContextOptions options) : base(options) { } public DbSet<Employee> Employees { get; set; } public DbSet<Department> Departments { get; set; } ... }
اما الان میخوام روشی رو معرفی کنم که دیگه نیاز نباشه تک تک این انتیتی ها رو دستی وارد کنید بلکه به صورت یکباره و داینامیک این کار انجام بشه. برای این کار لازمه یک کلاس Abstact یا یه Interface داشته باشیم تا تمام انتیتی هایی که میخوایم به صورت اتوماتیک add بشن ازش ارث بری کنن و اینطوری اونها رو شناسایی کنیم.
من معمولا پراپرتی هایی که توی همه مدل هام هستن رو توی یه کلاس میگذارم از چنین کلاسی استفاده میکنم تا دیگه فیلدهای تکراری رو وارد نکنم:
public abstract class BaseEntity { public int Id { get; set; } public DateTime CreationDate { get; set; } public DateTime? LastModifiedDate { get; set; } public bool IsDeleted { get; set; } }
بعد از اون تمام مدل هام از این کلاس ارث بری می کنن. برای نمونه کلاس Employee این طوری خواهد شد:
public class Employee : BaseEntity { public string FirstName { get; set; } public string LastName { get; set; } public string Position { get; set; } public string Office { get; set; } public int DepartmentId { get; set; } public Department Department { get; set; } }
حالا یه Extension method از ModelBuilder می سازم. توی این متد از Reflection استفاده شده و تمام کلاس هایی که از BaseEntity استفاده کردن رو پیدا میکنه و توی DbContext به عنوان یه انتیتی رجیستر میکنه:
public static class ModelBuilderExtensions { public static void RegisterAllEntities<BaseType>(this ModelBuilder modelBuilder, params Assembly[] assemblies) { IEnumerable<Type> types = assemblies.SelectMany(a => a.GetExportedTypes()) .Where(c => c.IsClass && !c.IsAbstract && c.IsPublic && typeof(BaseType).IsAssignableFrom(c)); foreach (Type type in types) modelBuilder.Entity(type); } }
دقت داشته باشید که کد بالا داره کلاس abstact مورد نظر ما رو که اینجا BaseEntity هست رو به صورت جنریک دریافت میکنه و لازمه که موقع استفاده از این متد کلاسمون رو بهش معرفی کنیم.
توی مرحله بعد کافیه از این متد توی OnModelCreating استفاده کنم. به این صورت:
protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); var entitiesAssembly = typeof(BaseEntity).Assembly; modelBuilder.RegisterAllEntities<BaseEntity>(entitiesAssembly); }
حالا با خیال آسوده مایگریشن بزنید و کارتون رو ادامه بدید :)