.net core2.x 自动注入 Entity(实体对象到上下文)
概要:有点老套,因为早在 .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(实体对象到上下文)的更多相关文章
- 简单两步快速学会使用Mybatis-Generator自动生成entity实体、dao接口和简单mapper映射(用mysql和oracle举例)
前言: mybatis-generator是根据配置文件中我们配置的数据库连接参数自动连接到数据库并根据对应的数据库表自动的生成与之对应mapper映射(比如增删改查,选择性增删改查等等简单语句)文件 ...
- 简单三步快速学会使用Mybatis-Generator自动生成entity实体、dao接口以及mapper映射文件(postgre使用实例)
前言: mybatis-generator是根据配置文件中我们配置的数据库连接参数自动连接到数据库并根据对应的数据库表自动的生成与之对应mapper映射(比如增删改查,选择性增删改查等等简单语句)文件 ...
- springboot 使用JPA自动生成Entity实体类的方法
1. 2. 3.添加数据库 4. 5. 6. 7.点击OK完成. 8.去掉红色波浪线方法. 9.配置数据源 完成!
- Objective-C中ORM的运用:实体对象和字典的相互自动转换
http://blog.csdn.net/cooldragon/article/details/18991973 iOS开发中基于ORM的框架很多,如SQLitePersistentObject,实际 ...
- 利用反射跟自定义注解拼接实体对象的查询SQL
前言 项目中虽然有ORM映射框架来帮我们拼写SQL,简化开发过程,降低开发难度.但难免会出现需要自己拼写SQL的情况,这里分享一个利用反射跟自定义注解拼接实体对象的查询SQL的方法. 代码 自定义注解 ...
- 实体对象,List泛型 转换为DataTable
/// <summary> /// 实体对象转换DataTable /// </summary> /// <param name ...
- Entity Framework 实体框架的形成之旅--利用Unity对象依赖注入优化实体框架(2)
在本系列的第一篇随笔<Entity Framework 实体框架的形成之旅--基于泛型的仓储模式的实体框架(1)>中介绍了Entity Framework 实体框架的一些基础知识,以及构建 ...
- Entity Framework Code First实体对象变动跟踪
Entity Framework Code First通过DbContext.ChangeTracker对实体对象的变动进行跟踪,实现跟踪的方式有两种:变动跟踪快照和变动跟踪代理. 变动跟踪快照:前面 ...
- Quartz与Spring集成 Job如何自动注入Spring容器托管的对象
在Spring中使用Quartz有两种方式实现:第一种是任务类继承QuartzJobBean,第二种则是在配置文件里定义任务类和要执行的方法,类和方法可以是普通类.很显然,第二种方式远比第一种方式来的 ...
随机推荐
- shell脚本自动化部署服务
shell脚本自动化部署 !/bin/bash #export PATH=$PATH:/export/maven/bin run_flag_dir="/data0/shell/deploy_ ...
- Java EE之表达式语言EL(上)
1.了解表达式语言 表达式语言(EL)用于在不使用脚本.声明或者表达式的情况下,在JSP页面中渲染数据. EL曾是JSTL 1.0规范(与JSP 1.2)中的一部分,并且只可以用作JSTL标签的特性. ...
- react-native命令行打包APK报错
我是根据react-native官网进行的react-native打包APK 我的步骤为 第一步就是生成密钥 第二步就是将密钥拷入 第三步:在\android\gradle.properties写入 ...
- codeforces-1138 (div2)
想法题是硬伤,面对卡题和卡bug的情况应对能力太差 A.求两个前缀和以及两个后缀和,相邻最小值的最大值. #include<iostream> using namespace std; ; ...
- 映像文件工具srec
目录 映像文件工具srec 介绍与帮助 常用例子 常用选项 一个实际的例子 hex转bin 数据填充 文件合并 文件分割 加入CRC 查看信息 使用命令集合的文本 详细文件格式的描述 附录:MDK的例 ...
- 验证性控件的使用--验证两个文本框至少有一个不为空CustomValidator
转:http://blog.163.com/zhaowencong_2010/blog/static/20402815220122103155643/ 有时候我们在注册一个帐号时要求我们留下电话号码, ...
- Node.js实战项目学习系列(1) 初识Node.js
前言 一直想好好学习node.js都是半途而废的状态,这次沉下心来,想好好的学习下node.js.打算写一个系列的文章大概10几篇文章,会一直以实际案例作为贯穿的学习. 什么是node Node.js ...
- 解决Ubuntu 17.10设置面板打不开的问题
问题描述 对于Ubuntu桌面系统我用得不多,最近安装了Ubuntu17.10使用,一直都没遇到什么大的问题,界面风格已经与Windows很相似,总体体验还不错.直到某一天我突然手痒痒把Dock面板从 ...
- Java String相关
一.String类的常用方法 1. int indexOf(String s) 字符串查找 2. int lastIndexOf(String str) 3. char charAt(int inde ...
- [再寄小读者之数学篇](2014-05-27 矩阵的迹与 Jacobian)
(from MathFlow) 设 $A=(a_{ij})$, 且定义 $$\bex \n_A f(A)=\sex{\cfrac{\p f}{\p a_{ij}}}. \eex$$ 试证: (1) $ ...