2012-07-24 109 views
2

我有以下EF代碼優先代碼。我收到以下例外情況:主鍵違例:使用EF代碼優先繼承

'GiftCouponPayment'不包含標識列。

表已在數據庫中成功創建。但是,我怎樣才能擺脫這種異常?此外,這種例外的原因是什麼?

注意:對於任何表模式,只要域模型(先用代碼描述)保留(並且可以查詢數據),我就可以。

enter image description here

繼續這個異常後,有另一個異常如下:

同時節省不爲他們的關係暴露的外鍵的屬性的實體時出錯。 EntityEntries屬性將返回null,因爲單個實體不能被識別爲異常的來源。通過在您的實體類型中公開外鍵屬性,可以更輕鬆地處理保存時的異常。有關詳細信息,請參閱InnerException。

{ 「PRIMARY KEY約束 'PK_dbo.PaymentComponent' 違反無法插入對象 'dbo.PaymentComponent' 重複鍵\ r \ n該語句已終止。」}

參考

  1. Entity Framework: Split table into multiple tables

注意:生成的數據庫模式如下所示。

enter image description here

代碼:

public class MyInitializer : CreateDatabaseIfNotExists<NerdDinners> 
{ 
    //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<PluralizingTableNameConvention>(); 

     //Fluent API - Table per Concrete Type (TPC) 
     modelbuilder.Entity<GiftCouponPayment>() 
      .Map(m => 
      { 
       m.MapInheritedProperties(); 
       m.ToTable("GiftCouponPayment"); 
      }); 

     modelbuilder.Entity<ClubCardPayment>() 
      .Map(m => 
      { 
       m.MapInheritedProperties(); 
       m.ToTable("ClubCardPayment"); 
      }); 
    } 

    public DbSet<GiftCouponPayment> GiftCouponPayments { get; set; } 
    public DbSet<ClubCardPayment> ClubCardPayments { get; set; } 
    public DbSet<Payment> 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<PaymentComponent> PaymentComponents { get; set; } 
    public DateTime PayedTime { get; set; } 
} 

客戶:

static void Main(string[] args) 
    { 
     Database.SetInitializer<NerdDinners>(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<PaymentComponent> comps = new List<PaymentComponent>(); 
      comps.Add(giftCouponPayment); 
      comps.Add(clubCardPayment); 

      var payment = new Payment { PaymentComponents = comps, PayedTime=DateTime.Now }; 
      db.Payments.Add(payment); 

      int recordsAffected = db.SaveChanges(); 
     } 
    } 
+0

你想要兩個或三個表嗎? – 2012-07-24 15:12:25

+0

如果你想要三個支付表,那麼你不應該使用'MapInheritedProperties()'。 – 2012-07-26 10:32:28

+0

MapInheritedProperties用於TPC/TPH。你正在要求TPT。您需要刪除MapInheritedProperties。 – 2012-07-26 10:38:37

回答

2

我看到我對TPC初步意見是不正確的,因爲你也是在基類中使用FK - 你看到PaymentComponent表嗎?在TPC繼承的情況下,它不應該在那裏。嘗試使用TPT繼承(從您的映射中刪除MapInheritedProperties)。這將以相同的正確數據庫結束。不要使用種子。 Id將由PaymentComponent表中的標識列控制(因爲它現在是這樣)。

+0

謝謝。我刪除了MapInheritedProperties和種子設置。現在我得到例外。 「跨多個實體或關聯共享的值在多個位置生成,請檢查該映射是否將EntityKey分割爲多個商店生成的列。」「具有相同關鍵字的項目已添加」。「 – Lijo 2012-07-26 13:05:00

2

在您PaymentComponent類裝飾用ID KeyAttribute

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

升級到4.3.1是一個問題嗎?如果沒有,我會這樣做。甚至EF5.0 RC(我還沒有用過那個!)。 – 2012-07-24 15:35:58

+1

有一個名爲[NuGet Package Explorer](http://npe.codeplex.com/)的工具,可以讓你下載VS之外的包。 – 2012-07-24 15:39:22

+0

即使使用Key屬性也會出現相同的錯誤。 [Key]來自System。 ComponentModel。 DataAnnotations; – Lijo 2012-07-26 05:58:50

3

你沒有指定爲您的TPC/TPT映射ID字段。即使有繼承,您也需要在不運行TPH映射時執行此操作。 (要注意,我也不確定在MapInheritedProperties()呼叫...這通常用於TPH ...不是TPT)

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

這需要從具體類型的每個類映射。如果是我,我會用TPH映射與GiftCoupon以及其他繼承映射一起使用,以便最終生成一個表,以使用鑑別器列來表示整個對象樹。

無論...你缺少你的基類中的另一件事是:

public byte[] Version { get; set; } 

而對於相關聯的映射:

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

它允許樂觀併發。

希望這會有所幫助,請告訴我,如果您需要進一步的幫助或澄清。