日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

Ef Core花里胡哨系列(10) 动态起来的 DbContext

發布時間:2024/1/5 41 coder
生活随笔 收集整理的這篇文章主要介紹了 Ef Core花里胡哨系列(10) 动态起来的 DbContext 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Ef Core花里胡哨系列(10) 動態起來的 DbContext

我們知道,DbContext有兩種托管方式,一種是AddDbContextAddDbContextFactory,但是呢他們各有優劣,例如工廠模式下性能更好呀等等。那么,我們能否自己托管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取出我們對應AppIdDbContext進行操作就可以了:

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的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。