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 ...
随机推荐
- Nexus搭建maven仓库并使用
一.基本介绍 参考:https://www.hangge.com/blog/cache/detail_2844.html https://blog.csdn.net/zhuguanbo/article ...
- 文盘Rust -- tonic-Rust grpc初体验
gRPC 是开发中常用的开源高性能远程过程调用(RPC)框架,tonic 是基于 HTTP/2 的 gRPC 实现,专注于高性能.互操作性和灵活性.该库的创建是为了对 async/await 提供一流 ...
- firewalld规则配置
firewalld规则配置 一.概念 动态防火墙 启动新规则时,不会像iptables一样,先清空规则,再启动所有规则,如此会对现在程序有影响,哪怕只是一条规则.而firewalld 规则变更不需要对 ...
- 2023-09-30:用go语言,给你一个整数数组 nums 和一个整数 k 。 nums 仅包含 0 和 1, 每一次移动,你可以选择 相邻 两个数字并将它们交换。 请你返回使 nums 中包含 k
2023-09-30:用go语言,给你一个整数数组 nums 和一个整数 k . nums 仅包含 0 和 1, 每一次移动,你可以选择 相邻 两个数字并将它们交换. 请你返回使 nums 中包含 k ...
- SSM(Spring+SpringMVC+MyBatis)框架集成
引言 进行SSM(Spring+SpringMVC+MyBatis)集成的主要原因是为了提高开发效率和代码可维护性.SSM是一套非常流行的Java Web开发框架,它集成了Spring框架.Sprin ...
- open3d -- voxel_down_sample
官网文档 parameter: Input: open3d.geometry.Pointcloud点云类 voxel_size: 体素单位长度 Return: 处理后的点云类 Description: ...
- 11g编译bbed
报错如下: make -f ins_rdbms.mk $ORACLE_HOME/rdbms/lib/bbed Linking BBED utility (bbed) rm -f /u01/app/or ...
- .NET6发布项目到腾讯云Windows2012R全网最详细教程
注意:本次使用腾讯云作为本次的演示 1.创建服务器及连接 1.1 请先在腾讯云.阿里云等创建实例 1.2 打开远程连接工具输入在腾讯云获取的公网iP输入计算机 1.3 根据图片点击连接 1.4 输入服 ...
- 通过HTML和JavaScript实现随机抽取幸运员工
需求描述: 公司经常会要求IT部门做一个随机抽取员工页面,今天我们通过HTML和JavaScript来实现 HTML 结构 首先,我们需要编写 HTML 代码来定义页面结构和元素.下面是 HTML 代 ...
- Ubuntu 编辑文件、安装、删除软件等常用命令(持续更新)
一.编辑文件 1. sudo vi 文件名,进入文件页面,如图: 2. 按 i 键或者 o 键,进入编辑,左下角出现---------INSERT---------信息 3. 输入完毕后,按ESC退出 ...