如何在EF Core实体模型映射中实现更清晰的领域类继承?
解决方案:EF Core业务逻辑与基础设施分离的继承映射问题
方案1:直接将业务类作为EF实体,用配置类分离映射逻辑
不需要额外创建GameEntity这类中间实体,而是把业务层的Game、GameFps直接作为EF Core的实体类型,将EF的模型配置逻辑放在基础设施层的配置类中,实现代码分离:
- 在
Application.Infrastructure项目中创建实体配置类:
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using Application.BusinessLogic; public class GameConfiguration : IEntityTypeConfiguration<Game> { public void Configure(EntityTypeBuilder<Game> builder) { // 配置鉴别器 builder.HasDiscriminator<string>("GameType") .HasValue<Game>("Base") .HasValue<GameFps>("FPS"); // 其他EF配置(比如字段映射、索引等) // 若需要懒加载,可在DbContext构造函数中全局配置:options.UseLazyLoadingProxies() builder.Property(g => g.Name).IsRequired().HasMaxLength(100); } }
- 在
ApplicationDbContext中加载基础设施层的配置:
protected override void OnModelCreating(ModelBuilder modelBuilder) { // 自动加载当前程序集下的所有IEntityTypeConfiguration实现 modelBuilder.ApplyConfigurationsFromAssembly(typeof(GameConfiguration).Assembly); base.OnModelCreating(modelBuilder); }
这种方式既保留了业务层的纯逻辑结构,又将EF的映射配置完全隔离在基础设施层,完美解决多继承限制带来的问题。
方案2:用组合模式替代实体继承(适合不能修改业务层结构的场景)
如果必须保留GameEntity这类中间层,可通过组合而非继承来关联业务对象:
- 调整基础设施层的实体结构:
public class GameEntity { public int Id { get; set; } // 组合业务层的Game对象 public Game BusinessObject { get; set; } } public class GameFpsEntity : GameEntity { // 覆盖为GameFps类型 public new GameFps BusinessObject { get; set; } }
- 在模型配置中处理鉴别器和嵌套对象映射:
builder.Entity<GameEntity>() .HasDiscriminator<string>("GameType") .HasValue<GameEntity>("Base") .HasValue<GameFpsEntity>("FPS"); // 配置业务对象的嵌套属性映射 builder.Entity<GameEntity>() .OwnsOne(e => e.BusinessObject, b => { b.Property(g => g.Name).IsRequired().HasMaxLength(100); // 其他业务属性映射 }); builder.Entity<GameFpsEntity>() .OwnsOne(e => e.BusinessObject, b => { b.Property(fps => fps.FpsSpecificProperty).IsRequired(); // 继承自Game的属性会自动继承配置 });
这种方式的缺点是需要处理嵌套对象的映射,会增加代码复杂度,仅推荐在无法修改业务层结构时使用。
内容的提问来源于stack exchange,提问作者ibocon
相关产品推荐
相关产品推荐

