ASP.NET MVC Code First:TPT继承下为已有Request添加新ChildB
问题分析与解决方案
首先得戳破核心误解:你用的TPT继承是用来实现**「is-a(是一个)」**关系的——也就是说,一个Request实例只能是RequestChildA或者RequestChildB中的一种,不能同时既是A又是B。EF默认会维护这种排他性,所以当你手动给新的RequestChildB设置已存在的RequestId=1时,EF会认为你要创建一个属于RequestChildB的全新父类实例,于是自动插入了新的Request记录,这就是问题的根源。
如果你的业务需求是一个Request同时拥有ChildA和ChildB(也就是「has-a(拥有一个)」关系),那继承就不适用了,得改成外键关联的设计,具体步骤如下:
1. 重构实体类设计
把RequestChildA和RequestChildB改成独立实体,通过外键关联到Request,而不是继承它:
public class Request { public int RequestId { get; set; } public DateTime CreationDate { get; set; } public string CreatedBy { get; set; } public bool Active { get; set; } // 导航属性:一个Request可以关联多个ChildA/ChildB public virtual ICollection<RequestChildA> ChildAs { get; set; } public virtual ICollection<RequestChildB> ChildBs { get; set; } } public class RequestChildA { // 给子类自己加主键 public int RequestChildAId { get; set; } public string RequestChildAProp1 { get; set; } public string RequestChildAProp2 { get; set; } // 外键关联Request public int RequestId { get; set; } public virtual Request Request { get; set; } } public class RequestChildB { // 给子类自己加主键 public int RequestChildBId { get; set; } public string RequestChildBProp1 { get; set; } public string RequestChildBProp2 { get; set; } // 外键关联Request public int RequestId { get; set; } public virtual Request Request { get; set; } }
2. 显式配置关联关系(可选但推荐)
在你的DbContext的OnModelCreating方法里明确配置外键,避免EF自动识别出错:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { // 配置RequestChildA和Request的一对多关系 modelBuilder.Entity<RequestChildA>() .HasRequired(a => a.Request) .WithMany(r => r.ChildAs) .HasForeignKey(a => a.RequestId); // 配置RequestChildB和Request的一对多关系 modelBuilder.Entity<RequestChildB>() .HasRequired(b => b.Request) .WithMany(r => r.ChildBs) .HasForeignKey(b => b.RequestId); }
3. 正确添加ChildB的代码
现在你就可以给已有的RequestId=1添加ChildB,不会再创建新的Request记录了:
var childB = new RequestChildB { RequestChildBProp1 = "Value1", RequestChildBProp2 = "Value2", RequestId = 1 // 直接关联已存在的Request }; db.RequestChildB.Add(childB); db.SaveChanges();
额外说明
如果非要坚持用继承的话,是做不到让一个Request同时属于两个子类的——这完全违背了继承的语义,继承是排他的,一个实体只能属于继承链中的一个具体子类。所以根据你的业务需求,外键关联才是正确的设计方向。
内容的提问来源于stack exchange,提问作者jomsk1e
相关产品推荐
相关产品推荐

