2011-11-21 53 views
14

實體框架代碼首先可以爲以下POCO生成DB。實體框架代碼優先:FOREIGN KEY約束可能導致循環或多個級聯路徑

public class Item { 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

public class ItemPair { 
    public int Id { get; set; } 

    public virtual Item FirstItem { get; set; } 
    public virtual Item SecondItem { get; set; } 
} 

我想通過ID字段而不是整個「Item」類建立與第一個和第二個項目的關係。所以:

public class ItemPair { 
    public int Id { get; set; } 

    public virtual Item FirstItem { get; set; } 
    public int FirstItem_Id { get; set; } 

    public virtual Item SecondItem { get; set; } 
    public int SecondItem_Id { get; set; } 
} 

也有效。 編輯:這實際上並沒有工作。只需生成其他FirstItem_Id1和SecontItem_Id2列。

但只是改變像這樣的外鍵屬性FirstItemId,SecondItemId,(不帶下劃線):

public class ItemPair { 
    public int Id { get; set; } 

    public virtual Item FirstItem { get; set; } 
    public int FirstItemId { get; set; } 

    public virtual Item SecondItem { get; set; } 
    public int SecondItemId { get; set; } 
} 

導致以下異常。

{"Introducing FOREIGN KEY constraint 'ItemPair_SecondItem' on table 'ItemPair' may cause 
cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, 
or modify other FOREIGN KEY constraints.\r\nCould not create constraint. 
See previous errors."} 

爲什麼?我能做些什麼來避免這種例外。

+0

這個替代方案幫助我更好http://stackoverflow.com/questions/19373310/introducing-foreign-key-constraint-may-cause-cycles-or-multiple-cascade-paths – Mzn

回答

17

我的期望是,在第一種情況下,您的Id屬性未在數據庫中使用,因爲FK和EF將創建另外兩列(可以通過使用ForeignKeyAttribute強制將導航屬性與FK屬性配對來驗證此屬性)。在第二種情況下,EF將正確識別您的屬性,但它也將使用級聯刪除約定,這會在SQL Server中導致錯誤。您有兩個指向同一父級的屬性。實際上,在數據庫中,您可以從相同的Item(兩個FK設置爲​​相同的Id)創建ItemPair。如果兩個關係都啓用級聯刪除,則會導致多個級聯路徑=>不允許在SQL Server中使用。

這裏的解決方案是流暢映射以手動定義關係如何映射。 Here就是這個例子。

+0

非常感謝。花了幾個小時試圖弄清楚。我沒有想到閱讀級聯刪除約定。 – Pauly

21

我決定刪除級聯刪除約定。

protected override void OnModelCreating(DbModelBuilder modelBuilder) { 
     base.OnModelCreating(modelBuilder); 

     modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); 
     modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>(); 

    } 

的原因是:

  • 我寧願標記刪除或停用用於審計記錄。
  • 我最多隻刪除了聯結/映射表。
  • 使用ORM在我需要的罕見情況下,循環訪問和刪除子記錄相對比較簡單。

謝謝Ladislav Mrnka指着我在正確的方向。

+0

感謝上帝,我已經閱讀了另一個類似問題的答案,並認爲我需要將所有基於屬性的映射都做得流利。恕我直言,EF試圖默認做太多。 – Josh

+0

我也有同樣的感覺,所以我也開始使用基於屬性的映射。不過,我現在使用Fluent API映射,因爲它似乎給了我更多的控制權,以及保持我的POCO免費。嘗試安裝「實體框架電源工具」並對當前數據庫進行逆向工程。我想,一旦你看到它產生的映射,它不會覺得這麼陌生。 – Pauly

+0

這看起來不錯!但不幸的是沒有在我的情況下工作。我沒有得到的是我如何在每一個關係上調用WillCascadeOnDelete(false),並刪除這個約定,仍然在我的SQL腳本中(詳細列表),我可以看到它創建了違規約束。在這個命令中是「ON DELETE CASCADE」,儘管我所有的工作都是流利的映射來消除這種行爲。 –

相關問題