EF CORE使用反射实现动态DbSet
为什么要动态配置DbSet?
在各种EF CORE的教程中我们可看到,配置DbContext数据库上下文的模型时都是手写具体的实体类名来添加
例如手动写DbSet:
public DbSet<Blog> Blogs { get; set; }
或者在OnModelCreating中进行配置
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.Url)
.IsRequired();
}
但这只适用于实体类比较少的情况下,如果业务量很大,用到几十上百张表,这样去配置DbContext就比较麻烦了(其实是太懒了)
实现
具体实现其实很简单,我们需要反射调用ModelBuilder.Entity方法的重载ModelBuilder.Entity<TEntity>(),看看MS DOC里它的描述:
Entity<TEntity>()
返回一个对象,该对象可用于配置模型中给定的实体类型。 如果实体类型不是模型的一部分,则会将其添加到模型中。
正常我们在OnModelCreating
调用该方法时是需要写明泛型类的,但是为了动态生成DbSet这样去写显然是不现实的,那么就需要通过反射来实现
首先,我们需要建一个专门存放实体类型的项目,或者你也可以放在现有的项目中,这里我假装有个叫 Model
的类库项目
然后创建一个实体类
namespace Model
{
[Table("Blog")]
public class Blog
{
}
}
这里用Table
这个Attribute来标识这个类是一个实体类,方便后面反射获取以及自定义表名,当然你也可以自定义Attribute或者接口来标识
当我们的程序引用了Model项目后就可以在运行时通过AppDomain
来获取程序集中定义的类信息,当然你也可以通过Assembly.LoadFile()
来手动指定程序集的路径进行加载
var definedTypes =
AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault(s => s.GetName().Name=="Model")
.DefinedTypes
.ToList();
然后我们可以通过获取接口或者Attribute的信息来过滤得到的类信息以免加载不需要的类
var entityTypes = definedTypes
.Where(o => o.GetCustomAttributes<Table>().Any())
.Where(o => o.IsClass && !o.IsAbstract && !o.IsGenericType)
.ToList();
下面通过反射获取Entity方法
var entityMethod = typeof(ModelBuilder).GetMethod("Entity", new Type[] { });
然后循环实体类信息集合,反射调用Entity方法生成实体
if (entityTypes is { Count: > 0 })
{
foreach (var type in entityTypes)
{
var entityBuilder = entityMethod
.MakeGenericMethod(type)
.Invoke(modelBuilder, new object[] { });
var hasKeyMethod = entityBuilder.GetType().GetMethod("HasKey", new Type[] { typeof(string[]) });
hasKeyMethod.Invoke(entityBuilder, new object[] { new string[] { "UID" } });
}
}
这里还通过HasKey
方法设定了主键,否则使用时会出现问题。EF CORE默认会把类名作为实体的表名,如果想自定义表名可以通过Table
Attribute获取自定义的表名然后反射调用ToTable
方法来设定
然后就可以通过DbContext.Set<T>()来获取DbSet<T>进行数据库操作了
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?