如何将EF6与EFCore实体统一映射到同一接口并避免类型转换异常
首先你的共享EntityTypes项目的多目标框架配置是合理的,通过公共接口统一不同EF版本实体的方案完全可行,遇到的转换错误是实体类未绑定接口导致的。
问题原因
你遇到的System.InvalidCastException本质原因是:EF 6、EF Core各自项目中的实体类没有继承共享项目中的IEntity接口,EF运行时生成的动态代理类自然也不满足接口约束,所以直接执行Cast<IEntity>()时会抛出转换失败异常。
解决方案
方案1:实体类显式实现公共接口(推荐)
这种方案性能最优,运行时无需额外转换开销。
步骤1:两边项目引用共享实体接口项目
确保.NET Framework 4.0项目和.NET Core项目都已经添加对EntityTypes共享项目的引用。
步骤2:修改实体类继承接口
根据你使用的EF模式调整:
- 若为Database First:修改两边的T4实体生成模板,让自动生成的实体类默认继承
EntityTypes.IEntity接口 - 若为Code First:手动给实体类添加接口继承即可
示例(EF 6端实体类调整后):
using EntityTypes; public partial class Entity : IEntity { // 以下两个属性是接口要求的属性,和原有实体属性保持一致即可 public long EntityID { get; set; } public string EntityName { get; set; } // 其他原有实体属性保持不变 }
EF Core 5.0端的实体类做同样的接口继承调整即可。
步骤3:调整通用方法的泛型约束
给你的泛型方法添加接口约束,编译期即可校验传入类型的合法性:
var _entitiesContext = new EntitiesContext(); // 增加IEntity约束 public static List<IEntity> BuildSet<T>() where T : class, IEntity { return _entitiesContext.Set<T>().ToList().Cast<IEntity>().ToList(); }
可选:关闭动态代理
如果不需要懒加载、变更追踪代理功能,可以在上下文配置中关闭代理生成,避免动态代理类型带来的额外兼容问题:
- EF 6端配置:
public EntitiesContext() : base("name=EntitiesContext") { this.Configuration.ProxyCreationEnabled = false; }
- EF Core 5.0端配置:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer("你的数据库连接字符串") .UseChangeTrackingProxies(false) .UseLazyLoadingProxies(false); }
方案2:映射转换适配(适用于不能修改原有实体类的场景)
如果因为历史代码限制不能修改原有实体类的继承关系,可以通过对象映射实现接口转换,推荐使用AutoMapper类库实现:
步骤1:配置映射关系
// 全局仅需配置一次 var mapperConfig = new MapperConfiguration(cfg => { // EF 6实体到IEntity的映射 cfg.CreateMap<EF6App.Entity, IEntity>(); // EF Core实体到IEntity的映射 cfg.CreateMap<EFCoreApp.Entity, IEntity>(); }); var mapper = mapperConfig.CreateMapper();
步骤2:查询时直接投影到接口
public static List<IEntity> BuildSet<T>() where T : class { // 直接在EF查询阶段投影,不会加载多余字段,性能更高 return _entitiesContext.Set<T>() .ProjectTo<IEntity>(mapper.ConfigurationProvider) .ToList(); }
这种方案不需要修改原有实体类的代码,也能实现统一接口返回的需求。
内容的提问来源于stack exchange,提问作者Ivan Silkin
相关产品推荐
相关产品推荐

