使用EntityFramework6在SQL Server存储子类列表的方案咨询
Entity Framework 6 中存储子类列表的可行方案
一、你首选的单表存储方案(TPH:表每层次)
完全可以实现你要的表结构 {ClassType NOT NULL, Id NOT NULL, Order NOT NULL, Quantity NULL, Price NULL},这是EF6默认支持的继承映射方式,所有继承层次的实体都存在同一张表,通过鉴别列区分不同子类。
实现步骤
调整模型字段可空性
子类专属字段在其他类型实体中无值,需改为可空值类型,否则数据库会强制非空导致插入失败:public abstract class Base { public int Id { get; set; } public int Order { get; set; } } public class Specific1 : Base { public int? Quantity { get; set; } // 改为可空 } public class Specific2 : Base { public int? Price { get; set; } // 改为可空 } public class Owner { public int Id { get; set; } public ICollection<Base> Children { get; set; } }DbContext配置
在OnModelCreating中配置鉴别列和表映射:public class MyDbContext : DbContext { public DbSet<Owner> Owners { get; set; } public DbSet<Base> Bases { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { // 配置基类主键与必填字段 var baseEntity = modelBuilder.Entity<Base>(); baseEntity.HasKey(b => b.Id); baseEntity.Property(b => b.Order).IsRequired(); // 配置鉴别列ClassType,指定不同子类对应的标识值 baseEntity.Map<Specific1>(m => m.Requires("ClassType").HasValue("Specific1")); baseEntity.Map<Specific2>(m => m.Requires("ClassType").HasValue("Specific2")); // 显式配置子类字段可空(模型已改为可空时可省略,这里做确认) modelBuilder.Entity<Specific1>().Property(s => s.Quantity).IsOptional(); modelBuilder.Entity<Specific2>().Property(s => s.Price).IsOptional(); // 配置Owner与Base的关联关系 modelBuilder.Entity<Owner>() .HasMany(o => o.Children) .WithRequired() .Map(m => m.MapKey("OwnerId")); } }
生成的表结构
执行迁移后,会生成符合你要求的单表:
ClassType: 非空,存储子类标识(如"Specific1")Id: 主键,非空Order: 非空Quantity: 可空Price: 可空
这种方案的优势是手动查询简单,直接通过ClassType过滤即可获取指定子类数据。
二、其他可行方案
1. 表每类型(TPT)
将基类和每个子类分别存放在不同表中,子类表通过主键关联基类表:
- 基类表
Base:Id,Order,OwnerId - 子类表
Specific1:Id,Quantity(Id为外键关联Base表) - 子类表
Specific2:Id,Price(Id为外键关联Base表)
配置示例:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<Base>().ToTable("Base"); modelBuilder.Entity<Specific1>().ToTable("Specific1"); modelBuilder.Entity<Specific2>().ToTable("Specific2"); }
优点是表结构更规范,子类字段可设为非空;缺点是手动查询需要关联多表,相对繁琐。
2. 表每具体类(TPC)
每个子类单独存放在一张表,包含基类的所有字段,无基类表:
Specific1表:Id,Order,Quantity,OwnerIdSpecific2表:Id,Order,Price,OwnerId
配置示例:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<Specific1>().Map(m => { m.MapInheritedProperties(); m.ToTable("Specific1"); }); modelBuilder.Entity<Specific2>().Map(m => { m.MapInheritedProperties(); m.ToTable("Specific2"); }); }
优点是查询单个子类时无需关联,性能较好;缺点是基类字段重复存储,手动查询不同子类需要切换表,维护成本高。
内容的提问来源于stack exchange,提问作者Anders Juul
相关产品推荐
相关产品推荐

