首先回顾下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. Math.ceil()、floor()、round()

    ceil():向上取整,>=某个小数的最小整数,即15.3取16.返回double类型 如果参数小于0且大于-1.0,结果为 -0. floor():向下取整,<=某个小数的最大整数,即1 ...

  2. 分享C#识别图片上的数字

    通过Emgu实现对图片上的数字进行识别.前期步骤:1.下载Emgu安装文件,我的版本是2.4.2.1777.3.0版本则实现对中文的支持.2.安装后需填写环境变量,环境变量Path值后加入Emgu安装 ...

  3. centos7下mysql双主+keepalived

    一.keepalived简介 keepalived是vrrp协议的实现,原生设计目的是为了高可用ipvs服务,keepalived能够配置文件中的定义生成ipvs规则,并能够对各RS的健康状态进行检测 ...

  4. AC日记——幸运号码 51nod 1043

    幸运号码 思路: 传说中的数位dp: 不难发现,n(n<1000) ,那么,n个数的最大和为9*1000=9000: 对于9000*1000的时间范围,我们可以用dp来解决: dp[i][j], ...

  5. Azure CDN 服务详解

    Azure CDN概述   Azure CDN(内容分发网络)是一种用于分发高带宽内容的全球CDN解决方案,它可以托管在Azure中,也可以通过在任何其他位置,借助Azure CDN,可以托管到任何其 ...

  6. webpack常用配置项配置文件介绍

    一.webpack基础 1.在项目中生成package.json:在项目根目录中输入npm init,根据提示输入相应信息.(也可以不生成package.json文件,但是package.json是很 ...

  7. ES6十大特性

    本文主要针对ES6做一个简要介绍. 主要译自:  http://webapplog.com/ES6/comment-page-1/.也许你还不知道ES6是什么, 实际上, 它是一种新的javascri ...

  8. MySQL备份工具收集

    说明:MySQL的备份不像SQL Server那么的简单,备份时需要分数据库引擎类型,现在主流的就两个:InnoDB和MyISAM,而这两种类型备份方式各不一样. MyISAM: mysqlhotco ...

  9. Maven错误:“No goals have been specified for this build...”问题解决

    如图出现如下错误: 解决方法如下: 1.(未测试)在pom.xml添加如下配置: <build> <defaultGoal>compile</defaultGoal> ...

  10. 【freeCodeCamp】免费晋级前台工程师呦!!!!

    首页地址:https://www.freecodecamp.org/ GitHub:https://github.com/freeCodeCamp/freeCodeCamp ============= ...