EF Core 不支持运行时动态添加已编译实体类,但可通过 Runtime Model Building 在 OnModelCreating 阶段用 ModelBuilder.Entity(Type) 等 API 动态配置模型;需借助 IModelCacheKeyFactory 实现多模型隔离,且不可修改已构建的只读 IModel。

EF Core 本身不支持在应用运行时“动态添加”已编译的实体类(比如 new Type() 然后直接注册),但可以通过 运行时构建模型(Runtime Model Building) 实现类似效果——即在程序启动后、DbContext 创建前,用代码定义实体结构、关系和映射,再注入到 EF Core 的元数据系统中。
使用 ModelBuilder 动态配置模型
这是最常用且官方推荐的方式。你可以在 DbContext.OnModelCreating 中根据条件或外部配置(如 JSON、数据库表结构)动态调用 ModelBuilder API:
- 用
modelBuilder.Entity或() modelBuilder.Entity(Type)注册类型 - 通过
.Property()、.HasKey()、.HasOne().WithMany()等链式方法配置属性、主键、关系 - 支持非泛型重载,可配合反射动态传入 Type 对象
示例:根据类型名字符串动态注册一个实体
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var entityType = Type.GetType("MyApp.Models.DynamicEntity");
if (entityType != null)
{
var entityBuilder = modelBuilder.Entity(entityType);
entityBuilder.HasKey("Id");
entityBuilder.Property("Name").HasMaxLength(100);
entityBuilder.Property("CreatedAt").HasDefaultValueSql("GETDATE()");
}
}用 IModelCacheKeyFactory 实现多租户/多模型隔离
当需要为不同租户、客户或场景加载不同实体集时,不能只靠单个 DbContext 类型。这时可自定义 IModelCacheKeyFactory,让 EF Core 根据上下文参数(如租户 ID)返回不同的模型缓存键,从而触发不同模型构建逻辑:
- 继承
IModelCacheKeyFactory并重写CreateCacheKey - 在
OnModelCreating中根据 key 决定加载哪些实体 - 配合依赖注入容器,按需解析 DbContext 实例
避免直接修改已构建的 IModel
EF Core 的 IModel 是只读快照,一旦 DbContext 第一次被使用,模型就冻结了。试图通过反射或内部 API 修改它会导致未定义行为或异常。所以“动态添加”必须发生在 OnModelCreating 阶段,或更早的 IDbContextOptionsExtension 扩展点中。
替代方案:Code-First + 运行时生成类(高级场景)
如果真需要完全未知结构(如用户上传 Excel 表并映射为数据库表),可结合以下技术:
- 用
System.Reflection.Emit或Microsoft.CodeAnalysis在内存中生成 C# 类型 - 将生成的 Type 传给
ModelBuilder.Entity(Type) - 配合
MigrationsAssembly和自定义IDatabaseProvider支持运行时迁移(较复杂,慎用)
注意:这种方式绕过了编译期检查,调试和维护成本高,建议仅用于低频、可控的元数据驱动场景(如 BI 工具后台)。
基本上就这些。核心原则是:EF Core 的模型构建是一次性、不可变的过程,所谓“动态”,本质是在构建阶段引入外部逻辑,而不是事后修改。










