Ef Core花里胡哨系列(10) 动态起来的 DbContext
Ef Core花里胡哨系列(10) 动态起来的 DbContext
我们知道,DbContext
有两种托管方式,一种是AddDbContext
和AddDbContextFactory
,但是呢他们各有优劣,例如工厂模式下性能更好呀等等。那么,我们能否自己托管DbContext
呢?
Github Demo:动态起来的 DbContext
场景:
结合我们之前的文章 [Ef Core花里胡哨系列(5) 动态修改追踪的实体、动态查询] 假设一个应用内有很多的子应用,且都需要更新追踪的动态实体,那么很多表在重置OnModelCreating
的时候将会非常的慢。主要体现在modelBuilder.Model.AddEntityType(type)
,每个实体都需要花费一小段时间,几百个实体就会按分钟计算了,而且还会数据库操作产生一定的影响。
我们先实现一个基础的DbContext
用来添加一些通用的实体以及处理动态实体的逻辑,每次需要重置DbContext的时候,都会获取最新的动态实体进行更新:
public class DbContextBase : DbContext
{
public DbSet<User> Users { get; set; } = null!;
public DbSet<Department> Departments { get; set; } = null!;
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Data Source=sample.db");
optionsBuilder.ReplaceService<IModelCacheKeyFactory, MyModelCacheFactory>();
base.OnConfiguring(optionsBuilder);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var name = GetType().Name.Split("_");
if (name.Length > 1)
{
foreach (var item in FormTypeBuilder.GetAppTypes(name[0]).Where(item => modelBuilder.Model.FindEntityType(item.Value) is null))
{
modelBuilder.Model.AddEntityType(item.Value);
}
}
base.OnModelCreating(modelBuilder);
}
}
然后实现一个动态DbContext
的生成器,用于针对不同的AppId
生成不同的DbContext
:
public class DbContextGenerator
{
private readonly ConcurrentDictionary<string, Type> _contextTypes = new()
{
};
public Type GetOrCreate(string appId)
{
if (!_contextTypes.TryGetValue(appId, out var value))
{
value = GeneratorDbContext(appId);
_contextTypes.TryAdd(appId, value);
}
return value;
}
public Type GeneratorDbContext(string appId)
{
var assemblyName = new AssemblyName("__RuntimeDynamicDbContexts");
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("__RuntimeDynamicModule");
var typeBuilder = moduleBuilder.DefineType($"{appId.ToLower()}_DbContext", TypeAttributes.Public | TypeAttributes.Class, typeof(DbContextBase));
var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { });
var ilGenerator = constructorBuilder.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Call, typeof(DbContextBase).GetConstructor(Type.EmptyTypes));
ilGenerator.Emit(OpCodes.Ret);
typeBuilder.CreateType();
var dbContextType = assemblyBuilder.GetType($"{appId.ToLower()}_DbContext");
return dbContextType;
}
}
然后我们需要实现一个DbContext
的容器用于管理我们生成的DbContext
,以及负责初始化:
public class DbContextContainer : IDisposable
{
private readonly DbContextGenerator _generator;
private readonly Dictionary<string, DbContext> _contexts = new();
public DbContextContainer(DbContextGenerator generator)
{
_generator = generator;
}
public DbContext Get(string appId)
{
if (!_contexts.TryGetValue(appId, out var context))
{
context = (DbContext)Activator.CreateInstance(_generator.GetOrCreate(appId))!;
_contexts[appId] = context;
}
return context;
}
public void Dispose()
{
_contexts.Clear();
}
}
DbContextContainer
的生命周期即DbContext
的生命周期,因为DbContext
的缓存是共享的,所以我们也不用担心一些性能问题。
使用时也非常简单,我们只需要在DbContextContainer
取出我们对应AppId
的DbContext
进行操作就可以了:
public class DynamicController : ApiControllerBase
{
private readonly DbContextContainer _container;
public DynamicController(DbContextContainer container)
{
_container = container;
}
[HttpGet]
public async Task<IActionResult> GetCompanies()
{
var res = await _container.Get("test1").DynamicSet(typeof(Company)).ToDynamicListAsync();
return Ok(res);
}
[HttpGet]
public async Task<IActionResult> AddCompany()
{
var db = _container.Get("test1");
FormTypeBuilder.AddDynamicEntity("test1", "Companies", typeof(Company));
db.UpdateVersion();
return Ok();
}
}
Ef Core花里胡哨系列(10) 动态起来的 DbContext的更多相关文章
- 在EF Core里面如何使用以前EntityFramework的DbContext.Database.SqlQuery<SomeModel>自定义查询
问: With Entity Framework Core removing dbData.Database.SqlQuery<SomeModel> I can't find a solu ...
- ASP.NET Boilerplate 学习 AspNet Core2 浏览器缓存使用 c#基础,单线程,跨线程访问和线程带参数 wpf 禁用启用webbroswer右键菜单 EF Core 2.0使用MsSql/MySql实现DB First和Code First ASP.NET Core部署到Windows IIS QRCode.js:使用 JavaScript 生成
ASP.NET Boilerplate 学习 1.在http://www.aspnetboilerplate.com/Templates 网站下载ABP模版 2.解压后打开解决方案,解决方案目录: ...
- EF Core 2.0使用MsSql/Mysql实现DB First和Code First
参考地址 EF官网 ASP.NET Core MVC 和 EF Core - 教程系列 环境 Visual Studio 2017 最新版本的.NET Core 2.0 SDK 最新版本的 Windo ...
- Asp.net core下利用EF core实现从数据实现多租户(2) : 按表分离
前言 在上一篇文章中,我们介绍了如何根据不同的租户进行数据分离,分离的办法是一个租户一个数据库. 也提到了这种模式还是相对比较重,所以本文会介绍一种更加普遍使用的办法: 按表分离租户. 这样做的好处是 ...
- EF Core 2.0中Transaction事务会对DbContext底层创建和关闭数据库连接的行为有所影响
数据库 我们先在SQL Server数据库中建立一个Book表: CREATE TABLE [dbo].[Book]( ,) NOT NULL, ) NULL, ) NULL, ) NULL, [Cr ...
- 9.10 翻译系列:EF数据注解特性之StringLength【EF 6 Code-First系列】
原文链接:https://www.entityframeworktutorial.net/code-first/stringlength-dataannotations-attribute-in-co ...
- 9.翻译系列:EF 6以及EF Core中的数据注解特性(EF 6 Code-First系列)
原文地址:http://www.entityframeworktutorial.net/code-first/dataannotation-in-code-first.aspx EF 6 Code-F ...
- 9.4 翻译系列:EF 6以及 EF Core中的NotMapped特性(EF 6 Code-First系列)
原文链接:http://www.entityframeworktutorial.net/code-first/notmapped-dataannotations-attribute-in-code-f ...
- 10.翻译系列:EF 6中的Fluent API配置【EF 6 Code-First系列】
原文链接:https://www.entityframeworktutorial.net/code-first/fluent-api-in-code-first.aspx EF 6 Code-Firs ...
- 10.1.翻译系列:EF 6中的实体映射【EF 6 Code-First系列】
原文链接:https://www.entityframeworktutorial.net/code-first/configure-entity-mappings-using-fluent-api.a ...
随机推荐
- vue2实现数据聚合【scatter-clustering】组件封装
实现如下效果: 效果展示:https://code.juejin.cn/pen/7228568245148581943 如果不会请移步到官网的栗子,请点击查看 直接给大家上代码: 整体代码片段 1 & ...
- C++在HotSpot VM中一种巧妙的内存管理方式
在HotSpot VM中定义了一个Relocation类及相关的子类,可以通过这些类操作不同的重定位数据,如在CodeCache中读写这些数据.这些类需要的内存很小,但是不同的类需要的内存大小又不一样 ...
- 03-11gR2单机通过RMAN恢复到RAC(未验证)
1.在单机上做一个完全备份,并将备份集拷贝到RAC的第一个节点上. 2.强行启动到nomount 3.恢复spfile 4.创建pfile,修改pfile,重建spfile #####修改contro ...
- P4899 [IOI2018] werewolf 狼人 题解
P4899 [IOI2018] werewolf 狼人 题解 题目描述 省流: \(n\) 个点,\(m\) 条边,\(q\) 次询问,对于每一次询问,给定一个起点 \(S\) 和终点 \(T\) , ...
- CC BY-SA 4.0原文及翻译
CC BY-SA 4.0原文及翻译 英文参考链接 中文参考链接 原文: Attribution 4.0 International (CC BY 4.0) This is a human-readab ...
- html部分兼容性总结
部分兼容性总结一下: 1.background-color的兼容性: 火狐正常,可以同时在后面加上!important(只有火狐识别,其他的不识别,火狐优先,位置必须放在开头). IE,谷歌,360, ...
- 把 map 中的 key 由驼峰命名转为下划线
import cn.hutool.core.util.StrUtil; /** * 把 map 中的 key 由驼峰命名转为下划线 */public HashMap<String, Object ...
- .Net Core 3.1 服务端配置跨域
一.在Startup.cs 的 ConfigureServices 配置好跨域策略 原文链接:https://www.jianshu.com/p/534b9a6a6ed5 public void Co ...
- Typora + PicGo 快乐书写 Markdown 文档
声明 以下提及的图床服务商跟本人无任何商业来往,你可以根据自己的需要选择其他更适合的服务商. 个人观点 这是一个服务付费的时代,相比于自己折腾.在价格适当,服务到位的情况下,我更倾向于选择商业服务.毕 ...
- NewsCenter
打开界面有一个搜索框 抓包查看是post形式提交的数据包 这时候试试sql注入,万能密码直接全都显示,那就说明存在sql注入漏洞 这里试试用sqlmap自动注入试试(POST类型的sql注入第一次尝试 ...