EF6&EFCore 注册/使用实体类的正确姿势
首先回顾下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 注册/使用实体类的正确姿势的更多相关文章
- Java 基础(三)| IO流之使用 File 类的正确姿势
为跳槽面试做准备,今天开始进入 Java 基础的复习.希望基础不好的同学看完这篇文章,能掌握泛型,而基础好的同学权当复习,希望看完这篇文章能够起一点你的青涩记忆. 一.什么是 File 类? java ...
- 无法为具有固定名称“MySql.Data.MySqlClient”的 ADO.NET 提供程序加载在应用程序配置文件中注册的实体框架提供程序类型“MySql.Data.MySqlClient.MySqlProviderServices,MySql.Data.Entity.EF6”
"System.InvalidOperationException"类型的未经处理的异常在 mscorlib.dll 中发生 其他信息: 无法为具有固定名称"MySql. ...
- 【技术】JavaSE环境下JPA实体类自动注册
在没有容器支持的环境下,JPA的实体类(Entity)一般要在persistence.xml中逐个注册,类似下面这样: <?xml version="1.0" encodin ...
- 讨论一下hibernate如何动态注册一个动态生成的实体类
如何动态生成实体类请参考这篇博文:http://www.cnblogs.com/anai/p/4269858.html 下面说说得到实体类后,如何能使用hibernate的接口来进行数据访问. 我们都 ...
- .NET Core、EF、Dapper、MySQL 多种方式实现数据库操作(动态注册实体类)
目录 前言 一.技术选型 二.遇到的坑 2.1..NET Core 下 EF 的问题 2.2.数据库实体类的注册 切记坑 前言 最近在学习.研究 .NET Core 方面的知识,动手搭建了一些小的 D ...
- 使用.net core efcore根据数据库结构自动生成实体类
源码 github,已更新最新代码 https://github.com/leoparddne/GenEntities/ 使用的DB是mysql,所有先nuget一下mysql.data 创建t4模板 ...
- NetCore +EFCore+SqlServer根据数据库生成实体类到项目中
转载自:https://www.cnblogs.com/yangjinwang/p/9516988.html 1.点击“工具”->“NuGet包管理器”->“程序包管理器控制台” 分别安装 ...
- 在efcore 中创建类 通过实现IEntityTypeConfiguration<T>接口 实现实体类的伙伴类 实现FluentApi
1 创建实体类: public partial class NewsCategory : IAggregationRoot { public NewsCategory() { } public Gui ...
- ASP.NET Core EFCore 之DBFirst 自动创建实体类和数据库上下文
通过引用Nuget包添加实体类 运行 Install-Package Microsoft.EntityFrameworkCore.SqlServer 运行 Install-Package Micros ...
随机推荐
- Python 函数的一般形式及参数
#!/usr/bin/env python # -*- coding:utf-8 -*- # @Time : 2017/11/01 21:46 # @Author : lijunjiang # @Fi ...
- Action 和 Func 的用法以及区别
Action 无返回值 Func 有返回值,且最后一个参数为返回值 Action用法 public static void test(string s) { Console.WriteLine(&qu ...
- CSU 1997: Seating Arrangement【构造】
1997: Seating Arrangement Description Mr. Teacher老师班上一共有n个同学,编号为1到n. 在上课的时候Mr. Teacher要求同学们从左至右按1, 2 ...
- 洛谷——P2781 传教
P2781 传教 题目背景 写完暑假作业后,bx2k去找pear玩.pear表示他要去汉中传教,于是bx2k准备跟着去围观. 题目描述 pear把即将接受传教的人排成一行,每个人从左到右的编号为1-n ...
- 2016集训测试赛(十八)Problem C: 集串雷 既分数规划学习笔记
Solution 分数规划经典题. 话说我怎么老是忘记分数规划怎么做呀... 所以这里就大概写一下分数规划咯: 分数规划解决的是这样一类问题: 有\(a_1, a_2 ... a_n\)和\(b_1, ...
- {dede:sql}标签的用法
sql标签可以称得上是个万能标签了,查询数据库将其输出,这里介绍一些关于这个标签的用法: 1.用来输出统计内容,这个是不错的,举个例子,我们来统计下总共发了多少的文章,思路就是输出dede_addon ...
- iscroll 子表左右滚动同时保持页面整体上下滚动
if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultExce ...
- Linux下报错:Segmentation fault.
遇到的问题:程序在读文件之后,准备执行fclose(fp);时,出现了如下错误: Program received signal SIGSEGV, Segmentation fault. 解决方法:倒 ...
- 深入Java----集合----BitSet
BitSet类 大小可动态改变, 取值为true或false的位集合.用于表示一组布尔标志. java中有三种移位运算符 << : 左移运算符,num <&l ...
- 过滤器Filter_03_多个Filter的执行顺序
过滤器Filter_03_多个Filter的执行顺序 学习了:https://www.cnblogs.com/HigginCui/p/5772514.html 按照在web.xml中的顺序进行filt ...