實體框架6:代碼優先級聯刪除

c# entity-framework entity-framework-6 sql

所以這裡有幾個類似的問題,但我仍然有問題確定我在簡化場景中缺少的是什麼。

假設我有以下表格,巧妙地以自己的名字命名:

'JohnsParentTable' (Id, Description) 
'JohnsChildTable' (Id, JohnsParentTableId, Description)

結果類看起來像這樣

public class JohnsParentTable
{
    public int Id { get; set; }
    public string Description { get; set; }
    public virtual ICollection<JohnsChildTable> JohnsChildTable { get; set; }

    public JohnsParentTable()
    {
        JohnsChildTable = new List<JohnsChildTable>();
    }
}

internal class JohnsParentTableConfiguration : EntityTypeConfiguration<JohnsParentTable>
{
    public JohnsParentTableConfiguration()
    {
        ToTable("dbo.JohnsParentTable");
        HasKey(x => x.Id);
        Property(x => x.Id).HasColumnName("Id").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        Property(x => x.Description).HasColumnName("Description").IsRequired().HasMaxLength(50);
    }
}

public class JohnsChildTable
{
    public int Id { get; set; }
    public string Description { get; set; }
    public int JohnsParentTableId { get; set; }
    public JohnsParentTable JohnsParentTable { get; set; }
}

internal class JohnsChildTableConfiguration : EntityTypeConfiguration<JohnsChildTable>
{
    public JohnsChildTableConfiguration()
    {
        ToTable("dbo.JohnsChildTable");
        HasKey(x => x.Id);
        Property(x => x.Id).HasColumnName("Id").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        Property(x => x.Description).HasColumnName("Description").IsRequired().HasMaxLength(50);
        HasRequired(a => a.JohnsParentTable).WithMany(c => c.JohnsChildTable).HasForeignKey(a => a.JohnsParentTableId);
    }
}

在數據庫中,我在父表中有一行,Id為1,子表中有兩行綁定到該父表。如果我這樣做:

var parent = db.JohnsParentTable.FirstOrDefault(a => a.Id == 1)

正確填充對象。但是,如果我嘗試刪除此行:

var parent = new Data.Models.JohnsParentTable() { Id = 1 };
db.JohnsParentTable.Attach(parent);
db.JohnsParentTable.Remove(parent);

db.SaveChanges();

實體框架嘗試執行以下操作:

DELETE [dbo].[JohnsParentTable]
WHERE ([Id] = @0)
-- @0: '1' (Type = Int32)
-- Executing at 1/23/2014 10:34:01 AM -06:00
-- Failed in 103 ms with error: The DELETE statement conflicted with the REFERENCE constraint "FK_JohnsChildTable_JohnsParentTable". The conflict occurred in database "mydatabase", table "dbo.JohnsChildTable", column 'JohnsParentTableId'.
The statement has been terminated.

那麼我的問題是我錯過了什麼以確保實體框架知道它必須在刪除父項之前刪除'JohnsChildTable'行?

一般承認的答案

這取決於您是希望實體框架刪除子項,還是希望數據庫處理它。

如果希望EF為所有子項生成delete語句並在刪除父項之前執行這些語句,則必須先將所有子項加載到內存中。

所以你不能簡單地只用填充的密鑰創建一個“虛擬”實體,並期望刪除子項。

為此,您必須讓數據庫處理刪除。

子表上的外鍵必須啟用級聯刪除。如果是這種情況,Entity Framework只為父級創建一個delete語句,數據庫也知道刪除子級。

如果需要關係,實體框架會創建一個默認啟用級聯刪除的外鍵,就像您的情況一樣。 (外鍵不能為空)。

如果您自己創建了數據庫,則必須記住啟用它。


熱門答案

我認為最好覆蓋OnModelCreating方法並添加此代碼。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
   modelBuilder.Entity<JohnsChildTable>()
               .HasRequired(t=>t.JohnsParentTable)
               .WithMany(t=>t.JohnsChildTables)
               .HasForeignKey(d=>d.JohnsParentTableId)
               .WillCascadeOnDelete(true);

            base.OnModelCreating(modelBuilder);
}

我設置為true WillCascadeOnDelete(true)



Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因