Ef Core花里胡哨系列(5) 动态修改追踪的实体、动态查询

发布时间 2024-01-02 15:51:50作者: 胖纸不争

Ef Core花里胡哨系列(5) 动态修改追踪的实体、动态查询

同样还是IModelCacheKeyFactory,不过这次要采用主动刷新的方式。

实现DbContext

动态实体,根据配置等生成动态类型来当作数据库实体使用,当配置修改时,可以调用DynamicModelCacheKeyFactory.Refresh()刷新DbContext。

动态构建部分不提供,我们将在其它的地方进行讨论。

public class SampleDbContext(DbContextOptions<SampleDbContext> options)
    : DbContext(options)
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // 构建所有的FormType
        FormTypeBuilderService.BuildFormTypes();

        // 将Type添加到DbContext上下文
        foreach (var type in FormTypeBuilderService.Value.GetModelTypes())
        {
            AddFormEntityType(type);
        }

        base.OnModelCreating(modelBuilder);

        void AddFormEntityType(Type formType)
        {
            var entityType = modelBuilder.Model.FindEntityType(formType);
            if (entityType == null)
            {
                modelBuilder.Model.AddEntityType(formType);
            }
            modelBuilder.Entity(formType).HasBaseType((Type)null!);
        }
    }
}

实现IModelCacheKeyFactory

我这里做了简化处理,直接检测了当前月份的变化,也可以通过实现一个静态变量由外部动态改变。

public class DynamicModelCacheKeyFactory : IModelCacheKeyFactory
{
    private static Guid RefreshToken = Guid.NewGuid();

    public static Guid Refresh() => Guid.NewGuid(); 

    public object Create(DbContext context, bool designTime)
    {
        return DateTime.Now.ToString("yyyyMM");
    }
}

替换DbContext中的默认实现

services.AddDbContext<SampleDbContext>(opts =>
{
    opts.ReplaceService<IModelCacheKeyFactory, DynamicModelCacheKeyFactory>();
});

派生DbContext内置方法

实现一个DynamicSet对标Set<T>,需要安装System.Linq.Dynamic.CoreMicrosoft.EntityFrameworkCore.DynamicLinq,即可使用lambda进行拼接查询。

public class SampleDbContext(DbContextOptions<SampleDbContext> options)
    : DbContext(options)
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // 构建所有的FormType
        FormTypeBuilderService.BuildFormTypes();

        // 将Type添加到DbContext上下文
        foreach (var type in FormTypeBuilderService.Value.GetModelTypes())
        {
            AddFormEntityType(type);
        }

        base.OnModelCreating(modelBuilder);

        void AddFormEntityType(Type formType)
        {
            var entityType = modelBuilder.Model.FindEntityType(formType);
            if (entityType == null)
            {
                modelBuilder.Model.AddEntityType(formType);
            }
            modelBuilder.Entity(formType).HasBaseType((Type)null!);
        }
    }

    public IQueryable DynamicSet(string tableId)
    {
        var type = FormTypeBuilderService.GetModelType(tableId);
        return (IQueryable)GetType().GetTypeInfo().GetMethod("Set", Type.EmptyTypes)!.MakeGenericMethod(type)
            .Invoke(this, null)!;
    }
}