EF Core 2.1自定义IEntityTypeAddedConvention与懒加载代理冲突报错求助
问题分析与解决方案
这个问题我之前碰到过,本质是EF Core生成的懒加载代理类触发了你的自定义约定,导致你尝试在派生的代理类上配置主键,而EF Core明确要求主键必须在根实体类型(也就是你自己定义的PermitPublication类)上配置,所以抛出了错误。
为什么会出现这个错误?
当你启用UseLazyLoadingProxies后,EF Core会在运行时动态生成实体类的派生代理类(比如PermitPublicationProxy),这些代理类会被自动添加到模型中,进而触发你的IEntityTypeAddedConvention的Apply方法。
你的原始代码没有判断当前处理的是不是代理类,直接对所有实体类型执行主键配置逻辑——而代理类是派生自你的原始实体的,EF Core不允许在派生类上设置主键,必须在根实体上操作,所以就出现了那个报错。
修复方案:修改自定义约定,跳过代理类与派生实体
我们只需要在Apply方法里添加判断,只在根实体类型(非代理、非派生的原始实体)上应用复合键配置。修改后的代码如下:
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata.Builders; using System.Reflection; public class CompositeKeyConvetion : IEntityTypeAddedConvention { public InternalEntityTypeBuilder Apply(InternalEntityTypeBuilder entityTypeBuilder) { Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); var entityType = entityTypeBuilder.Metadata; // 跳过代理类型和派生实体类型,只处理根实体 if (ProxyHelper.IsProxyType(entityType.ClrType) || entityType.BaseType != null) { return entityTypeBuilder; } if (entityType.HasClrType()) { var pks = entityType.ClrType .GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.IsDefined(typeof(CompositeKeyAttribute), false)) .ToList(); if (pks.Count > 0) { entityTypeBuilder.PrimaryKey(pks, ConfigurationSource.Convention); } } return entityTypeBuilder; } }
关键修改说明:
- 添加代理类型判断:用
ProxyHelper.IsProxyType(entityType.ClrType)识别EF Core生成的动态代理类,直接跳过处理。 - 添加派生实体判断:通过
entityType.BaseType != null跳过所有派生实体类型(包括TPH继承结构中的子实体),因为主键应该在父实体上配置,不需要重复设置。
这样修改后,你的约定只会在你自己定义的原始根实体上生效,不会再触及EF生成的代理类,懒加载代理启用后也不会再出现那个错误了。
内容的提问来源于stack exchange,提问作者alireza.salemian
相关产品推荐
相关产品推荐

