Ef Core花里胡哨系列(5) 动态修改追踪的实体、动态查询
同样还是IModelCacheKeyFactory
,不过这次要采用主动刷新的方式。
实现DbContext
动态实体,根据配置等生成动态类型来当作数据库实体使用,当配置修改时,可以调用DynamicModelCacheKeyFactory.Refresh()
刷新DbContext。
动态构建部分不提供,我们将在其它的地方进行讨论。
public class SampleDbContext(DbContextOptions<SampleDbContext> options): DbContext(options)
{protected override void OnModelCreating(ModelBuilder modelBuilder){// 构建所有的FormTypeFormTypeBuilderService.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.Core
和Microsoft.EntityFrameworkCore.DynamicLinq
,即可使用lambda进行拼接查询。
public class SampleDbContext(DbContextOptions<SampleDbContext> options): DbContext(options)
{protected override void OnModelCreating(ModelBuilder modelBuilder){// 构建所有的FormTypeFormTypeBuilderService.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)!;}
}