概要:有点老套,因为早在 .net frmework的时候(core还没出来),我们在使用 ef(4.。。。6)的时候就已经这么用,这里我在搭建框架,所以随手写下,让后来人直接拿去用用。

1.使用前提

  使用前我们一定要明白的是,通过fluent api去映射实体关系和属性的,也就是说core里面,要实现IEntityTypeConfiguration<TEntity>接口对象,示例如下:

public class UserRoleConfiguration : IEntityTypeConfiguration<UserRole>
{
public override void Configure(EntityTypeBuilder<UserRole> builder)
{
builder.HasMany(x => x.UserRolePermissionCollection).WithOne(x => x.UserRole).HasForeignKey(x => x.UserRoleID).IsRequired();
builder.HasDataRole();
}
}

  这时候我们可以在 DBContext的 onModelCreating中如下方式注入:

public class DbContextBase : DbContext, IDbContext
{
private readonly IEntityConfigurationFinder _configurationFinder;
public DbContextBase(DbContextOptions options, IEntityConfigurationFinder configurationFinder)
: base(options)
{
_configurationFinder = configurationFinder;
} protected override void OnModelCreating(ModelBuilder modelBuilder)
{
Type contextType = GetType();
IEntityRegister[] entityConfigures = _configurationFinder.GetEntityRegisters();
foreach (var config in entityConfigures)
{
config.Apply(modelBuilder);
}
}
}

  这是其中一个实体的映射方式,假设我们有十几或几十个,那么我们需要在这些十几或者几十遍,累得慌吧,累就对了,所以换个方式实现:

  我们在定义一个IEntityRegister对象,所有的 所有实体映射类都需要实现这个接口对象,接口如下:

public interface IEntityRegister
{
void Apply(ModelBuilder builder);
}

  同时修改上面的 roleEntityTypeConfiguration

public class UserRoleConfiguration : IEntityTypeConfiguration<UserRole>,IEntityRegister
{
public override void Configure(EntityTypeBuilder<UserRole> builder)
{
builder.HasMany(x => x.UserRolePermissionCollection).WithOne(x => x.UserRole).HasForeignKey(x => x.UserRoleID).IsRequired();
builder.HasDataRole();
}
public void Apply(ModelBuilder modelBuilder){
modelBuilder.ApplyConfiguration(this);
}
}

  

  这时候我们其他的几十个 实体的配置对象,依旧按照如上写法即可,现在我们要做的就是找到所有实现了IEntityRegister接口的对象,也就是实体的映射对象。

2.查找实体配置对象

  之前我们在上一篇说 dependencyInjection对象的时候,有写过一个类,其中查找程序及对象的方法,这里我们就又用到了,再贴一次完整的:

  接口实现:

/// <summary>
/// 查找应用程序中的程序集对象
/// </summary>
public interface IAppAssemblyFinder
{
/// <summary>
/// 查询所有程序集对象
/// </summary>
/// <param name="filterAssembly">是否排除非业务程序集对象</param>
/// <returns></returns>
Assembly[] FindAllAssembly(bool filterAssembly = true);
/// <summary>
/// 获取指定类型的对象集合
/// </summary>
/// <typeparam name="ItemType">指定的类型</typeparam>
/// <param name="expression">
/// 过滤表达式:
/// 查询接口(type=>typeof(ItemType).IsAssignableFrom(type));
/// 查询实体:type => type.IsDeriveClassFrom<ItemType>()
/// </param>
/// <param name="fromCache">是否从缓存查询</param>
/// <returns></returns>
Type[] FindTypes<ItemType>(Func<Type, bool> expression, bool fromCache = true) where ItemType : class;
}

  对应实现类:

public class AppAssemblyFinder : IAppAssemblyFinder
{
private List<Assembly> _assemblies = new List<Assembly>(); public Assembly[] FindAllAssembly(bool filterAssembly = true)
{
var filter = new string[]{
"System",
"Microsoft",
"netstandard",
"dotnet",
"Window",
"mscorlib",
"Newtonsoft",
"Remotion.Linq"
};
//core中获取依赖对象的方式
DependencyContext context = DependencyContext.Default;
if (context != null)
{
List<string> names = new List<string>();
string[] dllNames = context.CompileLibraries.SelectMany(m => m.Assemblies).Distinct().Select(m => m.Replace(".dll", "")).ToArray();
if (dllNames.Length > )
{
names = (from name in dllNames
let index = name.LastIndexOf('/') +
select name.Substring(index))
.Distinct()
.WhereIf(name => !filter.Any(name.StartsWith), filterAssembly)
.ToList();
}
return LoadFromFiles(names);
}
//传统方式
string pathBase = AppDomain.CurrentDomain.BaseDirectory;
string[] files = Directory.GetFiles(pathBase, "*.dll", SearchOption.TopDirectoryOnly)
.Concat(Directory.GetFiles(pathBase, ".exe", SearchOption.TopDirectoryOnly))
.ToArray();
if (filterAssembly)
{
files = files.WhereIf(f => !filter.Any(n => f.StartsWith(n, StringComparison.OrdinalIgnoreCase)), filterAssembly).Distinct().ToArray();
}
_assemblies = files.Select(Assembly.LoadFrom).ToList();
return _assemblies.ToArray();
} /// <summary>
/// 获取指定类型的对象集合
/// </summary>
/// <typeparam name="ItemType">指定的类型</typeparam>
/// <param name="expression"> 过滤表达式: 查询接口(type=>typeof(ItemType).IsAssignableFrom(type)); 查询实体:type => type.IsDeriveClassFrom<ItemType>()</param>
/// <param name="fromCache">是否从缓存查询</param>
/// <returns></returns>
public Type[] FindTypes<ItemType>(Func<Type, bool> expression, bool fromCache = true) where ItemType : class
{
List<Assembly> assemblies;
if (fromCache) assemblies = _assemblies;
if (_assemblies == null || _assemblies.Count() == )
assemblies = this.FindAllAssembly().ToList(); Type[] types = _assemblies.SelectMany(a => a.GetTypes())
.Where(expression).Distinct().ToArray(); return types;
}
/// <summary>
/// 从文件加载程序集对象
/// </summary>
/// <param name="files">文件(名称集合)</param>
/// <returns></returns>
private static Assembly[] LoadFromFiles(List<string> files)
{
List<Assembly> assemblies = new List<Assembly>();
files?.ToList().ForEach(f =>
{
AssemblyName name = new AssemblyName(f);
try { Assembly assembly = Assembly.Load(name); assemblies.Add(assembly); } catch { }
});
return assemblies.ToArray();
} }

  需要注意的是,这个接口以及实现类,需要注册为 singleton对象,保证生命周期和应用程序一致,否则,参数的fromCache无效,性能也会急剧下降。

  查找IEntityRegister对象:

public class EntityConfigFinder : IEntityConfigFinder
{
public EntityConfigFinder(IAppAssemblyFinder assemblyFinder)
{
_assemblyFinder = assemblyFinder;
} private readonly IAppAssemblyFinder _assemblyFinder; public IEntityRegister[] EntityRegisters()
{
var baseType = typeof(IEntityRegister);
var types = _assemblyFinder.FindTypes<IEntityRegister>(type => baseType.IsAssignableFrom(type));
var entityRegisters = types.Select(t => (IEntityRegister)Activator.CreateInstance(t))?.ToArray();
return entityRegisters;
}
}

  这时候我们就可以很简单的使用了:

3.使用

public class DbContextBase : DbContext, IDbContext
{
public DbContextBase(DbContextOptions options, IEntityConfigFinder entityFinder)
: base(options)
{
_entityConfigFinder = entityFinder;
} private readonly IEntityConfigFinder _entityConfigFinder; protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var dbContextType = GetType();
IEntityRegister[] entityRegisters = _entityConfigFinder.EntityRegisters();
foreach (var entityConfig in entityRegisters)
{
entityConfig.RegistTo(modelBuilder);
Console.WriteLine($"成功注册实体:{entityConfig.EntityType}");
}
Console.WriteLine($"成功注册实体:{entityRegisters.Length}个");
}
}
}

4.其他

  在 ef(6.x)中我们使用EntityTypeConfiguration的时候,可以直接使用该对象,但是core中没有了,所以我们可以再封装一个实现类:

public abstract class EntityTypeConfigurationBase<TEntity, TKey> : IEntityTypeConfiguration<TEntity>, IEntityRegister
where TEntity : class, IEntity<TKey>
{
/// <summary>
/// 将当前实体类映射对象注册到数据上下文模型构建器中
/// </summary>
/// <param name="modelBuilder">上下文模型构建器</param>
public void Apply(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(this);
} /// <summary>
/// 重写以实现实体类型各个属性的数据库配置
/// </summary>
/// <param name="builder">实体类型创建器</param>
public abstract void Configure(EntityTypeBuilder<TEntity> builder);
}

  这时候,我们的实体的配置类只需要继承该类,并实现其方法就可以了,比如:

public class UserRoleConfiguration : EntityTypeConfigurationBase<UserRole, Guid>
{
public override void Configure(EntityTypeBuilder<UserRole> builder)
{
builder.HasMany(x => x.UserRolePermissionCollection).WithOne(x => x.UserRole).HasForeignKey(x => x.UserRoleID).IsRequired();
builder.HasDataRole();
}
}

  DbContext的 OnModelCreating中不变。

结束!

.net core2.x 自动注入 Entity(实体对象到上下文)的更多相关文章

  1. 简单两步快速学会使用Mybatis-Generator自动生成entity实体、dao接口和简单mapper映射(用mysql和oracle举例)

    前言: mybatis-generator是根据配置文件中我们配置的数据库连接参数自动连接到数据库并根据对应的数据库表自动的生成与之对应mapper映射(比如增删改查,选择性增删改查等等简单语句)文件 ...

  2. 简单三步快速学会使用Mybatis-Generator自动生成entity实体、dao接口以及mapper映射文件(postgre使用实例)

    前言: mybatis-generator是根据配置文件中我们配置的数据库连接参数自动连接到数据库并根据对应的数据库表自动的生成与之对应mapper映射(比如增删改查,选择性增删改查等等简单语句)文件 ...

  3. springboot 使用JPA自动生成Entity实体类的方法

    1. 2. 3.添加数据库 4. 5. 6. 7.点击OK完成. 8.去掉红色波浪线方法. 9.配置数据源 完成!

  4. Objective-C中ORM的运用:实体对象和字典的相互自动转换

    http://blog.csdn.net/cooldragon/article/details/18991973 iOS开发中基于ORM的框架很多,如SQLitePersistentObject,实际 ...

  5. 利用反射跟自定义注解拼接实体对象的查询SQL

    前言 项目中虽然有ORM映射框架来帮我们拼写SQL,简化开发过程,降低开发难度.但难免会出现需要自己拼写SQL的情况,这里分享一个利用反射跟自定义注解拼接实体对象的查询SQL的方法. 代码 自定义注解 ...

  6. 实体对象,List泛型 转换为DataTable

    /// <summary>        /// 实体对象转换DataTable        /// </summary>        /// <param name ...

  7. Entity Framework 实体框架的形成之旅--利用Unity对象依赖注入优化实体框架(2)

    在本系列的第一篇随笔<Entity Framework 实体框架的形成之旅--基于泛型的仓储模式的实体框架(1)>中介绍了Entity Framework 实体框架的一些基础知识,以及构建 ...

  8. Entity Framework Code First实体对象变动跟踪

    Entity Framework Code First通过DbContext.ChangeTracker对实体对象的变动进行跟踪,实现跟踪的方式有两种:变动跟踪快照和变动跟踪代理. 变动跟踪快照:前面 ...

  9. Quartz与Spring集成 Job如何自动注入Spring容器托管的对象

    在Spring中使用Quartz有两种方式实现:第一种是任务类继承QuartzJobBean,第二种则是在配置文件里定义任务类和要执行的方法,类和方法可以是普通类.很显然,第二种方式远比第一种方式来的 ...

随机推荐

  1. 进程初识和multiprocessing模块之Process

    一.什么是进程 进程就是运行中的程序 进程是操作系统中最小的资源分配单位 进程与进程之间的关系 : 数据隔离的 进程的id:Process id = pid pid是一个全系统唯一的对某个进程的标识, ...

  2. Django+Vue打造购物网站(七)

    个人中心功能开发 drf文档注释 http://www.django-rest-framework.org/topics/documenting-your-api/ 动态设置serializer和pe ...

  3. Django 序列化

    序列化 背景 对于Django 的queryset 对象在传递给 前端的时候,前端是无法识别的 因此需要存在一个转换过程将 queryset 对象转换成 字符串前端才可以识别 演示 QuerySet ...

  4. Django JSON,AJAX

    JSON 概念 JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation) JSON 是轻量级的文本数据交换格式 JSON 独立于语言 * JSON 具 ...

  5. webpack学习记录 - 学习webpack-dev-server(三)

    怎么用最简单的方式搭建一个服务器? 首先安装插件 npm i --save-dev webpack-dev-server 然后修改 packet.json 文件 "scripts" ...

  6. 【mysql】mysql基准测试

    基准测试定义 基准测试其实是一种测量和评估软件性能指标的方法,用于建立某个时间点的性能基准,以便当系统的软硬件发生变化的时候重新进行基准测试以评估变化对性能的影响.所以对系统性能的测量,才能知道我们的 ...

  7. 洛谷P1880 石子合并(环形石子合并 区间DP)

    题目描述 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分. 试设计出1个算法,计算出将N堆石子合并成1 ...

  8. Android sdk platform,sdk tools,sdk Build tools,sdk platform tools 的关系

    1. sdk platform 简单理解为系统版本 最新级别: 28:Android 9 27:Android 8.1 26:Android 8.0 25:Android 7.1 24:Android ...

  9. mysql加速导入数据的简单设置

    mysql加速导入数据的简单设置 # 修改前查询参数值 show variables like 'foreign_key_checks'; show variables like 'unique_ch ...

  10. MySQL初步

    一 写在开头1.1 本节内容本节的主要内容是MySQL的基本操作(来自MySQL 5.7官方文档). 1.2 工具准备一台装好了mysql的ubuntu 16.04 LTS机器. 二 MySQL的连接 ...