主键冲突:使用EF Code Firstinheritance

我有以下EF代码的第一个代码。 我收到以下exception:

‘GiftCouponPayment’不包含标识列。

表已在数据库中成功创建。 但是,我怎样才能摆脱这种exception呢? 另外,这个例外的原因是什么?

注意:我可以使用任何表模式,因为域模型(首先使用代码描述)被保留(并且可以查询数据)。

在此处输入图像描述

继续此exception后,还有另一个例外,如下所示:

保存不公开其关系的外键属性的实体时发生错误。 EntityEntries属性将返回null,因为无法将单个实体标识为exception的来源。 通过在实体类型中公开外键属性,可以更轻松地在保存时处理exception。 有关详细信息,请参阅InnerException。

{“违反PRIMARY KEY约束’PK_dbo.PaymentComponent’。无法在对象’dbo.PaymentComponent’中插入重复键。\ r \ n语句已终止。”}

参考

  1. entity framework:将表拆分为多个表

注意 :生成的数据库模式如下所示。

在此处输入图像描述

码:

public class MyInitializer : CreateDatabaseIfNotExists { //Only one identity column can be created per table. protected override void Seed(NerdDinners context) { //context.Database.ExecuteSqlCommand("CREATE UNIQUE INDEX IX_Payment_PayedTime ON Payment (PayedTime)"); context.Database.ExecuteSqlCommand("DBCC CHECKIDENT ('Payment', RESEED, 1)"); context.Database.ExecuteSqlCommand("DBCC CHECKIDENT ('GiftCouponPayment', RESEED, 2)"); context.Database.ExecuteSqlCommand("DBCC CHECKIDENT ('ClubCardPayment', RESEED, 3)"); } } //System.Data.Entity.DbContext is from EntityFramework.dll public class NerdDinners : System.Data.Entity.DbContext { public NerdDinners(string connString): base(connString) { } protected override void OnModelCreating(DbModelBuilder modelbuilder) { //Fluent API - Plural Removal modelbuilder.Conventions.Remove(); //Fluent API - Table per Concrete Type (TPC) modelbuilder.Entity() .Map(m => { m.MapInheritedProperties(); m.ToTable("GiftCouponPayment"); }); modelbuilder.Entity() .Map(m => { m.MapInheritedProperties(); m.ToTable("ClubCardPayment"); }); } public DbSet GiftCouponPayments { get; set; } public DbSet ClubCardPayments { get; set; } public DbSet Payments { get; set; } } public abstract class PaymentComponent { public int PaymentComponentID { get; set; } public int MyValue { get; set; } public abstract int GetEffectiveValue(); } public partial class GiftCouponPayment : PaymentComponent { public override int GetEffectiveValue() { if (MyValue < 2000) { return 0; } return MyValue; } } public partial class ClubCardPayment : PaymentComponent { public override int GetEffectiveValue() { return MyValue; } } public partial class Payment { public int PaymentID { get; set; } public List PaymentComponents { get; set; } public DateTime PayedTime { get; set; } } 

客户:

  static void Main(string[] args) { Database.SetInitializer(new MyInitializer()); string connectionstring = "Data Source=.;Initial Catalog=NerdDinners;Integrated Security=True;Connect Timeout=30"; using (var db = new NerdDinners(connectionstring)) { GiftCouponPayment giftCouponPayment = new GiftCouponPayment(); giftCouponPayment.MyValue=250; ClubCardPayment clubCardPayment = new ClubCardPayment(); clubCardPayment.MyValue = 5000; List comps = new List(); comps.Add(giftCouponPayment); comps.Add(clubCardPayment); var payment = new Payment { PaymentComponents = comps, PayedTime=DateTime.Now }; db.Payments.Add(payment); int recordsAffected = db.SaveChanges(); } } 

我看到我对TPC的初步建议不正确,因为你也在基类中使用FK – 你看到了PaymentComponent表吗? 在TPCinheritance的情况下不应该存在。 尝试使用TPTinheritance(从映射中删除MapInheritedProperties )。 这将以相同的正确数据库结束。 不要使用种子。 Id将仅由PaymentComponent表中的标识列控制(就像此时一样)。

您没有为TPC / TPT映射指定ID字段。 即使使用inheritance,您也需要在不运行TPH映射时执行此操作。 (要注意,我也不确定MapInheritedProperties()调用…这通常用于TPH …而不是TPT)

  //Fluent API - Table per Concrete Type (TPC) modelbuilder.Entity() .HasKey(x => x.PaymentComponentID) .Map(m => { m.MapInheritedProperties(); m.ToTable("GiftCouponPayment"); }) .Property(x => x.PaymentComponentID) .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 

这需要在具体类型的每个类映射上。 如果是我,我将使用TPH映射,其中GiftCoupon以及其他inheritance映射,因此您最终使用1个表来使用鉴别器列表示整个对象树。

无论如何……基类中缺少的另一件事是:

 public byte[] Version { get; set; } 

以及相关的映射:

 Property(x => x.Version).IsConcurrencyToken() 

这允许乐观并发。

希望这有点帮助,如果您需要进一步的帮助或澄清,请告诉我。

在您的PaymentComponent类上使用KeyAttribute修饰ID

 [Key] public int PaymentComponentID { get; set; }