首先回顾下EF中常规使用流程

1.新建实体类以及实体配置(data annotation或fluent api)

    [Table("Users")]
public class Users
{
[Key]
public Guid Id { get; set; } [StringLength()]
public string Name { get; set; }
}

2.新建数据库上下文类MyDbContext

     public class MyDbContext : DbContext
{
public MyDbContext() { } public DbSet<Users> Users { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("connectionString");
} protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}

3.开始欢乐的操作Users

            using (MyDbContext context = new MyDbContext())
{
context.Users.FirstOrDefaultAsync(r => r.Name == "老王");
}

一切看起来都是很美好的,但假如有一天你面对上千个实体的时候,你可能会开始想用代码生成器.EF6中你还可以用modelBuilder.RegisterEntityType(type);那么现在又有一个新的要求,需要能同时使用data annotation和fluent api进行实体配置.自动根据约定注册实体,自动注册fluent api配置类.EF中注册实体的本质就是注册DbSet,方法非常多.

ok,直接贴代码,EF6:

       /// <summary>
/// 注册某个程序集中所有<typeparamref name="TEntityBase"/>的非抽象实体子类
/// </summary>
/// <typeparam name="TEntityBase">实体基类</typeparam>
/// <param name="modelBuilder"></param>
/// <param name="assembly">注册程序集</param>
public static void RegisterEntitiesFromAssembly<TEntityBase>(this DbModelBuilder modelBuilder, Assembly assembly)
where TEntityBase : class
{
modelBuilder.RegisterEntitiesFromAssembly(assembly, r => !r.IsAbstract && r.IsClass && r.IsChildTypeOf<TEntityBase>());
} /// <summary>
/// 注册某个程序集中所有<typeparamref name="TEntityBase"/>的非抽象实体子类
/// </summary>
/// <typeparam name="TEntityBase">实体基类</typeparam>
/// <param name="modelBuilder"></param>
/// <param name="assembly">注册程序集</param>
/// <param name="assembly">注册程序集</param>
public static void RegisterEntitiesFromAssembly(this DbModelBuilder modelBuilder, Assembly assembly, Func<Type, bool> entityTypePredicate)
{
if (assembly == null)
throw new ArgumentNullException(nameof(assembly)); //反射得到DbModelBuilder的Entity方法
var entityMethod = modelBuilder.GetType().GetMethod("Entity"); //反射得到ConfigurationRegistrar的Add<TEntityType>方法
var addMethod = typeof(ConfigurationRegistrar)
.GetMethods()
.Single(m =>
m.Name == "Add"
&& m.GetGenericArguments().Any(a => a.Name == "TEntityType"));
//扫描所有fluent api配置类,要求父类型必须是EntityTypeConfiguration<TEntityType>
var configTypes = assembly
.GetTypesSafely()
.Where(t =>
!t.IsAbstract && t.BaseType != null && t.IsClass
&& t.BaseType.IsGenericType
&& t.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>)
)
.ToList(); HashSet<Type> registedTypes = new HashSet<Type>(); //存在fluent api配置的类,必须在Entity方法之前调用
configTypes.ForEach(mappingType =>
{
var entityType = mappingType.BaseType.GetGenericArguments().Single();
if (!entityTypePredicate(entityType))
return;
var map = Activator.CreateInstance(mappingType);
//反射调用ConfigurationRegistrar的Add方法注册fluent api配置,该方法会同时注册实体
addMethod.MakeGenericMethod(entityType)
.Invoke(modelBuilder.Configurations, new object[] { map }); registedTypes.Add(entityType);
}); //反射调用Entity方法 注册实体
assembly
.GetTypesSafely()
.Where(entityTypePredicate)
.ForEach_(r =>
{
entityMethod.MakeGenericMethod(r).Invoke(modelBuilder, new object[]);
});
}

EFCore:

  /// <summary>
/// 注册某个程序集中所有<typeparamref name="TEntityBase"/>的非抽象子类为实体
/// </summary>
/// <typeparam name="TEntityBase">实体基类</typeparam>
/// <param name="modelBuilder"></param>
/// <param name="assembly">注册程序集</param>
public static void RegisterEntitiesFromAssembly<TEntityBase>(this ModelBuilder modelBuilder, Assembly assembly)
where TEntityBase : class
{
modelBuilder.RegisterEntitiesFromAssembly(assembly, r => !r.IsAbstract && r.IsClass && r.IsChildTypeOf<TEntityBase>());
} /// <summary>
/// 注册某个程序集中所有<typeparamref name="TEntityBase"/>的非抽象子类为实体
/// </summary>
/// <typeparam name="TEntityBase">实体基类</typeparam>
/// <param name="modelBuilder"></param>
/// <param name="assembly">注册程序集</param>
/// <param name="assembly">注册程序集</param>
public static void RegisterEntitiesFromAssembly(this ModelBuilder modelBuilder, Assembly assembly, Func<Type, bool> entityTypePredicate)
{
if (assembly == null)
throw new ArgumentNullException(nameof(assembly)); //反射得到ModelBuilder的ApplyConfiguration<TEntity>(...)方法
var applyConfigurationMethod = modelBuilder.GetType().GetMethod("ApplyConfiguration"); //所有fluent api配置类
var configTypes = assembly
.GetTypesSafely()
.Where(t =>
!t.IsAbstract && t.BaseType != null && t.IsClass
&& t.IsChildTypeOfGenericType(typeof(IEntityTypeConfiguration<>))).ToList(); HashSet<Type> registedTypes = new HashSet<Type>();
//存在fluent api配置的类,必须在Entity方法之前调用
configTypes.ForEach(mappingType =>
{
var entityType = mappingType.GetTypeInfo().ImplementedInterfaces.First().GetGenericArguments().Single(); //如果不满足条件的实体,不注册
if (!entityTypePredicate(entityType))
return; var map = Activator.CreateInstance(mappingType);
applyConfigurationMethod.MakeGenericMethod(entityType)
.Invoke(modelBuilder, new object[] { map }); registedTypes.Add(entityType);
}); assembly
.GetTypesSafely()
.Where(r => !registedTypes.Contains(r))
.Where(entityTypePredicate)
.ForEach_(r =>
{
//直接调用Entity方法注册实体
modelBuilder.Entity(r);
});
}

如何使用(EFCore,EF6类似)

        protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.RegisterEntitiesFromAssembly<IEntity>(this.GetType().Assembly);
} using (MyDbContext context = new MyDbContext())
{
context.Set<Users>().FirstOrDefaultAsync(r => r.Name == "老王");
}

data annotation和fluent api同时使用怎么用?,其中data annotation与fluent api冲突时,以fluent api为准,如Users的表名称最终会映射为"Users___",见代码

     [Table("Users")]
public class Users
{
[Key]
public Guid Id { get; set; } [StringLength()]
public string Name { get; set; }
} public class UsersMapping : IEntityTypeConfiguration<Users>
{
public void Configure(EntityTypeBuilder<Users> builder)
{
builder.ToTable("Users___");
}
}

不用你写 public DbSet<Users> Users{get;set;},也不用你写一大堆的,modelBuilder.ApplyConfiguration<Users>(new UserMpping());

一句代码modelBuilder.RegisterEntitiesFromAssembly<IEntity>(this.GetType().Assembly);搞定所有的实体与实体配置

代码:https://github.com/280780363/Lazy

最新文章

  1. HP滤波原理浅学
  2. 54-locate 简明笔记
  3. WinForm------分页控件dll下载地址
  4. matlab中各种高斯相关函数
  5. [cmd]linux 常用命令
  6. Spark on Yarn年度知识整理
  7. jsDoc注释的规范
  8. C#播放音乐,调用程序
  9. 数据类型转换中的一些特殊情况(JY06-JavaScript)
  10. C++ overloading contructor
  11. Java基础(1) - 语法 &amp; 概念
  12. IIS前端页面不显示详细错误解决方法
  13. Spring ioc 详解
  14. SQL server脚本语句积累
  15. Uber是如何重新思考GPS定位的(尤其是在城市峡谷中)
  16. expect 批量自动部署ssh 免密登陆
  17. 蒟蒻浅谈树链剖分之一——两个dfs操作
  18. LNMP(二)
  19. 数据库隔离级别深入理解(ORACLE)
  20. 测试:fiddler使用

热门文章

  1. Android build code command
  2. Qualcomm 專業名詞
  3. JDBC加载驱动的方法+statement
  4. C#生成高清缩略图的方法
  5. springBoot 数组增加工具类包
  6. 10.1综合强化刷题 Day7
  7. Oracle数据库搭建
  8. opentracing学习入门
  9. delphi 按位运算 not and or xor shl shr
  10. JVM —— 移除永久代