EntityFramework Core报Role实体需定义主键但实际无该实体的问题咨询
环境信息
当前使用的组件版本为 Microsoft.EntityFrameworkCore.InMemory 3.1.2。
问题背景
此前进行了重构操作,将模型拆分到不同程序集的独立上下文中。新创建的上下文运行正常,但旧上下文抛出如下错误:
The entity type 'Role' requires a primary key to be defined. If you intended to use a keyless entity type call 'HasNoKey()',
但当前旧上下文中已经不存在Role类型了。
已经尝试了以下排查手段,均无法解决问题:
- 全文检索,未找到任何Role相关引用
- 符号检索,未找到任何Role相关引用
- 清理解决方案后重新生成,问题依然存在
- 删除bin和obj文件夹,问题依然存在
- 重启Visual Studio,问题依然存在
也查询了模型缓存相关的资料,通常迁移会存储模型的表示数据,但我使用的是内存数据库,每次运行都应该生成全新实例才对。
堆栈信息
at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidateNonNullPrimaryKeys(IModel model, IDiagnosticsLogger`1 logger) at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger) at Microsoft.EntityFrameworkCore.Metadata.Conventions.ValidatingConvention.ProcessModelFinalized(IConventionModelBuilder modelBuilder, IConventionContext`1 context) at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelFinalized(IConventionModelBuilder modelBuilder) at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelFinalized(IConventionModelBuilder modelBuilder) at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.FinalizeModel() at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel() at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder) at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder) at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel() at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model() at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__7_3(IServiceProvider p) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies() at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider() at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies() at Microsoft.EntityFrameworkCore.DbContext.get_Model() at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityType() at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityQueryable() at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.System.Linq.IQueryable.get_Provider() at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source, Expression`1 predicate) ...
咨询问题
请问是什么原因导致模型仍被旧引用持有,或是存在其他潜在问题?有什么可行的排查解决方向?
原因分析
这类问题核心和EF Core的模型扫描规则、隐性依赖、缓存逻辑相关,常见触发点如下:
- 导航属性隐式引入:EF Core默认约定会自动把实体导航属性关联的类型加入上下文模型,哪怕你没有显式声明
DbSet<Role>。如果旧上下文残留的某个实体有指向Role的导航属性(包括基类中定义的属性、泛型属性),就会触发这个问题。 - 模型配置扫描范围问题:如果旧上下文的
OnModelCreating方法中调用了ApplyConfigurationsFromAssembly加载实体配置,没有限制程序集范围,就可能扫到拆分后其他程序集中的Role实体配置,自动把Role加入模型。 - 模型缓存复用:EF Core的模型默认按上下文类型全局缓存,和你用不用内存数据库无关。如果依赖注入时上下文注册为单例,或者复用了根服务容器,模型只会构建一次,旧版本的模型会被一直复用。
- 隐性程序集引用:旧上下文所在的项目隐式引用了存放Role模型的新程序集,EF Core扫描时会加载到对应的类型。
排查解决步骤
- 在旧上下文的
OnModelCreating方法开头加断点,调试时遍历modelBuilder.Model.GetEntityTypes()的返回结果,确认Role是否真的被加入模型,以及对应的来源程序集。 - 逐一检查旧上下文中所有实体的属性定义,清理残留的Role类型导航属性,包括基类、接口中定义的关联属性。
- 调整实体配置加载逻辑,如果用了
ApplyConfigurationsFromAssembly,明确指定只扫描旧上下文所在的程序集,或者过滤掉Role相关的配置类。 - 临时在
OnModelCreating中加入modelBuilder.Ignore<Role>();测试,如果编译提示找不到Role类型,说明存在动态加载的隐性依赖,可进一步检查项目的所有程序集引用。 - 测试是否为缓存导致:上下文配置时添加
options.EnableServiceProviderCaching(false),重启运行看问题是否消失,如果消失说明是模型缓存复用的问题,调整上下文的依赖注入生命周期为Scope即可。 - 检查项目依赖树,确认旧上下文所在项目没有引用存放新模型的程序集。
内容的提问来源于stack exchange,提问作者farlee2121
相关产品推荐
相关产品推荐

