首先回顾下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

EF6&EFCore 注册/使用实体类的正确姿势的更多相关文章

  1. Java 基础(三)| IO流之使用 File 类的正确姿势

    为跳槽面试做准备,今天开始进入 Java 基础的复习.希望基础不好的同学看完这篇文章,能掌握泛型,而基础好的同学权当复习,希望看完这篇文章能够起一点你的青涩记忆. 一.什么是 File 类? java ...

  2. 无法为具有固定名称“MySql.Data.MySqlClient”的 ADO.NET 提供程序加载在应用程序配置文件中注册的实体框架提供程序类型“MySql.Data.MySqlClient.MySqlProviderServices,MySql.Data.Entity.EF6”

    "System.InvalidOperationException"类型的未经处理的异常在 mscorlib.dll 中发生 其他信息: 无法为具有固定名称"MySql. ...

  3. 【技术】JavaSE环境下JPA实体类自动注册

    在没有容器支持的环境下,JPA的实体类(Entity)一般要在persistence.xml中逐个注册,类似下面这样: <?xml version="1.0" encodin ...

  4. 讨论一下hibernate如何动态注册一个动态生成的实体类

    如何动态生成实体类请参考这篇博文:http://www.cnblogs.com/anai/p/4269858.html 下面说说得到实体类后,如何能使用hibernate的接口来进行数据访问. 我们都 ...

  5. .NET Core、EF、Dapper、MySQL 多种方式实现数据库操作(动态注册实体类)

    目录 前言 一.技术选型 二.遇到的坑 2.1..NET Core 下 EF 的问题 2.2.数据库实体类的注册 切记坑 前言 最近在学习.研究 .NET Core 方面的知识,动手搭建了一些小的 D ...

  6. 使用.net core efcore根据数据库结构自动生成实体类

    源码 github,已更新最新代码 https://github.com/leoparddne/GenEntities/ 使用的DB是mysql,所有先nuget一下mysql.data 创建t4模板 ...

  7. NetCore +EFCore+SqlServer根据数据库生成实体类到项目中

    转载自:https://www.cnblogs.com/yangjinwang/p/9516988.html 1.点击“工具”->“NuGet包管理器”->“程序包管理器控制台” 分别安装 ...

  8. 在efcore 中创建类 通过实现IEntityTypeConfiguration<T>接口 实现实体类的伙伴类 实现FluentApi

    1 创建实体类: public partial class NewsCategory : IAggregationRoot { public NewsCategory() { } public Gui ...

  9. ASP.NET Core EFCore 之DBFirst 自动创建实体类和数据库上下文

    通过引用Nuget包添加实体类 运行 Install-Package Microsoft.EntityFrameworkCore.SqlServer 运行 Install-Package Micros ...

随机推荐

  1. Ubuntu备份设置与恢复

    打开家目录,按CTRL+H,显示所有隐藏文件,把所有文件名前面带点的文件(比如 .config).目录备份即可下次有问题就覆盖它

  2. Codeforces 898 C.Phone Numbers-STL(map+set+vector)

    C. Phone Numbers   time limit per test 2 seconds memory limit per test 256 megabytes input standard ...

  3. [LOJ6235]区间素数个数

    题目大意: 给定$n(n\leq10^{11})$,求$\pi(n)$. 思路: 计算$\pi$函数有$O(n^{\frac23})$的Lehmer算法,这里考虑$O(\frac{n^{\frac34 ...

  4. apache url rewrite问题

    apache RewriteEngine Your browser sent a request that this server could not understand http://www.ra ...

  5. Docker镜像原理和最佳实践

    https://yq.aliyun.com/articles/68477 https://yq.aliyun.com/articles/57126  DockerCon 2016 深度解读: Dock ...

  6. 【2019】问题记录一:后端获取URL参数的值内加号“+”变成空格“ ”

    问题:URL参数中加号“+”变成空格“ ” 一.现象     URL如:http://example.****.com/controller/action?param=rice+cook+panda ...

  7. Genymotion下载模拟器失败解决方案

    下载模拟器的时候经常出现下面的问题:(Connection timeout occurred) 解决方法: 1.查看你要下载的模拟器的版本,我要下的版本是6.0.0 2.到C:\Users\yourn ...

  8. Android性能优化第(一)篇---基本概念

    最近打算总结几篇app性能优化方面的东西,毕竟android弄了这么久,万一到哪些转了行,岁月久了就忘记了,纯粹当个人笔记.今个是第一篇---性能优化的基本概念,毛主席说了,让理论先行,理论指导实践. ...

  9. HDU1421

    提交啦n次一直WA,这个bug找啦几个小时,最终才发现数组开小啦,真是遗憾.这是一个典型的DP问题,题目要求从n个中选出k对使得最终疲劳度最小.首先对物品质量a[n]进行一次排序,用dp[i][j]表 ...

  10. 黑苹果+win10双系统折腾笔记

    寒假趁机在家折腾一下黑苹果 笔记本配置:神船K610D I7 4600 ,其他配置思路一样,驱动要自己找 镜像和工具:OS X Yosemite 10.10.3 镜像 WIN10 TLSB 2016 ...