繼上篇文章(EF Core懶人小技巧之拒絕DbSet)之後,最近筆者把這個小功能單獨封裝成一個擴充套件方法並開源,歡迎交流和Star~
GitHub: EntityFrameworkCore.Extension.AutoMapping
Nuget:EntityFrameworkCore.Extension.AutoMapping
EntityFrameworkCore.Extension.AutoMapping.Abp
EntityFrameworkCore.Extension.AutoMapping.AbpVNext
如何使用
在DbContext.cs中重寫OnModelCreating方法:
using EntityFrameworkCore.Extension;
... //此處省略其它程式碼
public class XmateDbContext:DbContext
{
... //此處省略其它程式碼
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var modelAssemblyName = "XMate.Models";//實體類所在類庫的名稱,不包含副檔名(.dll)
modelBuilder.AutoMappingEntityTypes<IEntity>(modelAssemblyName);//泛型IEntity為所有實體類的規約型別
base.OnModelCreating(modelBuilder);//這個必須加,否則報錯
...//此處省略其它程式碼
}
}
這樣,我們就可以不用寫滿屏的DbSet了。
但是,在有的第三方框架中可能就會誕生新的問題。。。
比如在ABP或者VNext框架中,用過ABP框架的都應該知道,ABP是透過掃描DbContext中的DbSet來實現將實體類的倉儲自動註冊到IOC容器中的,下面我們就需要自己動手來實現:
public static class AutoRegisterEntityRepositoryExtensions
{
/// <summary>
/// 將資料表實體型別對應的倉儲注入到IOC容器
/// </summary>
/// <param name="iocManager"></param>
public static void RegisterDbEntityRepositories<TDbContext>(this IIocManager iocManager, string modelAssemblyName) where TDbContext : DbContext
{
foreach (var entityType in GetDbEntityType(typeof(IEntity<>), modelAssemblyName))
{
var keyType = entityType.GetInterfaces().Where(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEntity<>)).SelectMany(t => t.GetGenericArguments()).First();
var genericRepositoryType = typeof(IRepository<,>).MakeGenericType(entityType, keyType);
var impType = typeof(EfCoreRepositoryBase<,,>).MakeGenericType(typeof(TDbContext), entityType, keyType);
iocManager.RegisterIfNot(genericRepositoryType, impType, lifeStyle: DependencyLifeStyle.Transient);
}
}
/// <summary>
/// 獲取資料表實體型別列表
/// </summary>
/// <param name="constraintType">實體定義約束型別</param>
/// <param name="modelAssemblyName">實體類所在dll名稱,不包含字尾名(.dll)</param>
/// <returns></returns>
private static List<Type> GetDbEntityType(Type constraintType, string modelAssemblyName)
{
var all = AppDomain.CurrentDomain.GetAssemblies();
var types = all.WhereIf(!modelAssemblyName.IsNullOrWhiteSpace(), a => a.FullName.Contains(modelAssemblyName))
.SelectMany(m => m.GetTypes().Where(t => t.IsClass && !t.IsAbstract && (t.IsImplement(constraintType) || t.IsSubclass(constraintType))).ToList())
.Distinct()
.ToList();
return types.Where(t => !t.GetCustomAttributes<NotMappedAttribute>().Any()).ToList();
}
}
注:以上程式碼摘自:AutoRegisterEntityRepositoryExtensions.cs
在ABP VNext中的實現思路也是如此,這裡就不貼程式碼了,感興趣的可以查閱原始碼
在Abp中實現自動注入實體類對應的Repository
using EntityFrameworkCore.Extension.AutoMapping.Abp;
... //此處省略其它程式碼
public class XmateModule:AbpModule
{
... //此處省略其它程式碼
//重寫Initialize方法
public override void Initialize()
{
... //此處省略其它程式碼
var modelAssemblyName = "XMate.Models";//實體類所在類庫的名稱,不包含副檔名(.dll)
IocManager.RegisterDbEntityRepositories(modelAssemblyName);
}
}
在Abp VNext中實現自動注入實體類對應的Repository
using EntityFrameworkCore.Extension.AutoMapping.AbpVNext;
... //此處省略其它程式碼
public class XmateModule:AbpModule
{
... //此處省略其它程式碼
//重寫ConfigureServices方法
public override void ConfigureServices(ServiceConfigurationContext context)
{
... //此處省略其它程式碼
var modelAssemblyName = "XMate.Models";//實體類所在類庫的名稱,不包含副檔名(.dll)
context.Services.RegisterDbEntityRepositories(modelAssemblyName);
}
}