efcore 实体配置_EF6&EFCore 注册/使用实体类的正确姿势

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

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

[Table("Users")]public classUsers

{

[Key]public Guid Id { get; set; }

[StringLength(10)]public string Name { get; set; }

}

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

1 public classMyDbContext : DbContext2 {3 publicMyDbContext() { }4

5 public DbSet Users { get; set; }6

7 protected override voidOnConfiguring(DbContextOptionsBuilder optionsBuilder)8 {9 optionsBuilder.UseSqlServer("connectionString");10 }11

12 protected override voidOnModelCreating(ModelBuilder modelBuilder)13 {14 base.OnModelCreating(modelBuilder);15 }16 }

3.开始欢乐的操作Users

using (MyDbContext context = newMyDbContext())

{

context.Users.FirstOrDefaultAsync(r=> r.Name == "老王");

}

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

ok,直接贴代码,EF6:

///

///注册某个程序集中所有的非抽象实体子类///

/// 实体基类

///

/// 注册程序集

public static void RegisterEntitiesFromAssembly(thisDbModelBuilder modelBuilder, Assembly assembly)where TEntityBase : class{

modelBuilder.RegisterEntitiesFromAssembly(assembly, r=> !r.IsAbstract && r.IsClass && r.IsChildTypeOf());

}///

///注册某个程序集中所有的非抽象实体子类///

/// 实体基类

///

/// 注册程序集

/// 注册程序集

public static void RegisterEntitiesFromAssembly(this DbModelBuilder modelBuilder, Assembly assembly, FuncentityTypePredicate)

{if (assembly == null)throw newArgumentNullException(nameof(assembly));//反射得到DbModelBuilder的Entity方法

var entityMethod = modelBuilder.GetType().GetMethod("Entity");//反射得到ConfigurationRegistrar的Add方法

var addMethod = typeof(ConfigurationRegistrar)

.GetMethods()

.Single(m=>m.Name== "Add"

&& m.GetGenericArguments().Any(a => a.Name == "TEntityType"));//扫描所有fluent api配置类,要求父类型必须是EntityTypeConfiguration

var configTypes =assembly

.GetTypesSafely()

.Where(t=>

!t.IsAbstract && t.BaseType != null &&t.IsClass&&t.BaseType.IsGenericType&& t.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>)

)

.ToList();

HashSet registedTypes = new HashSet();//存在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[0]);

});

}

View Code

EFCore:

1 ///

2 ///注册某个程序集中所有的非抽象子类为实体3 ///

4 /// 实体基类

5 ///

6 /// 注册程序集

7 public static void RegisterEntitiesFromAssembly(thisModelBuilder modelBuilder, Assembly assembly)8 where TEntityBase : class

9 {10 modelBuilder.RegisterEntitiesFromAssembly(assembly, r => !r.IsAbstract && r.IsClass && r.IsChildTypeOf());11 }12

13 ///

14 ///注册某个程序集中所有的非抽象子类为实体15 ///

16 /// 实体基类

17 ///

18 /// 注册程序集

19 /// 注册程序集

20 public static void RegisterEntitiesFromAssembly(this ModelBuilder modelBuilder, Assembly assembly, FuncentityTypePredicate)21 {22 if (assembly == null)23 throw newArgumentNullException(nameof(assembly));24

25 //反射得到ModelBuilder的ApplyConfiguration(...)方法

26 var applyConfigurationMethod = modelBuilder.GetType().GetMethod("ApplyConfiguration");27

28 //所有fluent api配置类

29 var configTypes =assembly30 .GetTypesSafely()31 .Where(t =>

32 !t.IsAbstract && t.BaseType != null &&t.IsClass33 && t.IsChildTypeOfGenericType(typeof(IEntityTypeConfiguration<>))).ToList();34

35 HashSet registedTypes = new HashSet();36 //存在fluent api配置的类,必须在Entity方法之前调用

37 configTypes.ForEach(mappingType =>

38 {39 var entityType =mappingType.GetTypeInfo().ImplementedInterfaces.First().GetGenericArguments().Single();40

41 //如果不满足条件的实体,不注册

42 if (!entityTypePredicate(entityType))43 return;44

45 var map =Activator.CreateInstance(mappingType);46 applyConfigurationMethod.MakeGenericMethod(entityType)47 .Invoke(modelBuilder, new object[] { map });48

49 registedTypes.Add(entityType);50 });51

52 assembly53 .GetTypesSafely()54 .Where(r => !registedTypes.Contains(r))55 .Where(entityTypePredicate)56 .ForEach_(r =>

57 {58 //直接调用Entity方法注册实体

59 modelBuilder.Entity(r);60 });61 }

View Code

如何使用(EFCore,EF6类似)

protected override voidOnModelCreating(ModelBuilder modelBuilder)

{

modelBuilder.RegisterEntitiesFromAssembly(this.GetType().Assembly);

}using (MyDbContext context = newMyDbContext())

{

context.Set().FirstOrDefaultAsync(r => r.Name == "老王");

}

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

1 [Table("Users")]2 public classUsers3 {4 [Key]5 public Guid Id { get; set; }6

7 [StringLength(10)]8 public string Name { get; set; }9 }10

11 public class UsersMapping : IEntityTypeConfiguration

12 {13 public void Configure(EntityTypeBuilderbuilder)14 {15 builder.ToTable("Users___");16 }17 }

View Code

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值