2013-03-05 44 views
30

的EntityFramework的文檔指出以下行爲是可能的:EntityFramewok:如何配置級聯刪除,以抵消外鍵

If a foreign key on the dependent entity is nullable, Code First does not set cascade delete on the relationship, and when the principal is deleted the foreign key will be set to null.

(從http://msdn.microsoft.com/en-us/jj591620

但是,我無法實現這樣的行爲。

我有代碼優先定義的以下實體:

public class TestMaster 
{ 
    public int Id { get; set; } 
    public string Name { get; set; }   
    public virtual ICollection<TestChild> Children { get; set; }  
} 

public class TestChild 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public virtual TestMaster Master { get; set; } 
    public int? MasterId { get; set; } 
} 

這裏是流利API映射配置:

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<TestMaster>() 
        .HasMany(e => e.Children) 
        .WithOptional(p => p.Master).WillCascadeOnDelete(false); 

     modelBuilder.Entity<TestChild>() 
        .HasOptional(e => e.Master) 
        .WithMany(e => e.Children) 
        .HasForeignKey(e => e.MasterId).WillCascadeOnDelete(false); 
    } 

外鍵是可空的,導航屬性被映射爲可選的,因此我期望級聯刪除像MSDN中描述的那樣工作 - 即,使所有子級的MasterID無效,然後刪除Master對象。

但是當我真正嘗試刪除,我得到FK違反錯誤:

using (var dbContext = new TestContext()) 
     { 
      var master = dbContext.Set<TestMaster>().Find(1); 
      dbContext.Set<TestMaster>().Remove(master); 
      dbContext.SaveChanges(); 
     } 

在調用SaveChanges()它拋出以下幾點:

System.Data.Entity.Infrastructure.DbUpdateException : An error occurred while updating the entries. See the inner exception for details. 
----> System.Data.UpdateException : An error occurred while updating the entries. See the inner exception for details. 
----> System.Data.SqlClient.SqlException : The DELETE statement conflicted with the REFERENCE constraint "FK_dbo.TestChilds_dbo.TestMasters_MasterId". The conflict occurred in database "SCM_Test", table "dbo.TestChilds", column 'MasterId'. 
The statement has been terminated. 

難道我做錯了什麼或做了我誤解了MSDN的說法?

回答

42

它的確如所描述的那樣工作,但MSDN上的文章沒有強調它只有在兒童也加載到上下文中時纔有效,不僅僅是父實體。因此,而不是使用Find(只加載父),則必須使用預先加載與Include(或其他任何方式向孩子們加載到上下文):

using (var dbContext = new TestContext()) 
{ 
    var master = dbContext.Set<TestMaster>().Include(m => m.Children) 
     .SingleOrDefault(m => m.Id == 1); 
    dbContext.Set<TestMaster>().Remove(master); 
    dbContext.SaveChanges(); 
} 

這將從數據庫中刪除主,將Child實體中的所有外鍵設置爲null,並將子項的UPDATE語句寫入數據庫。

+7

粗體文本救了我。延遲加載很好,但確保子對象在刪除之前加載... – amaters 2013-12-17 20:14:49

+0

我正在嘗試此示例。但在「包含」中出現錯誤。它說「不能將lamba表達式轉換爲類型」字符串「,因爲它不是委託類型」....我缺少什麼?謝謝 – Diego 2017-05-19 12:56:09

0

以下@ Slauma的偉大答案後,我仍然得到同樣的錯誤作爲OP。

所以,不要像我一樣天真,並認爲下面的例子會以相同的結果結束。

dbCtx.Entry(principal).State = EntityState.Deleted; 
dbCtx.Dependant.Where(d => d.PrincipalId == principalId).Load(); 

// code above will give error and code below will work on dbCtx.SaveChanges() 

dbCtx.Dependant.Where(d => d.PrincipalId == principalId).Load(); 
dbCtx.Entry(principal).State = EntityState.Deleted; 

首先負載孩子的來龍去脈以前設置實體狀態來刪除(如果你正在做這樣的說法)。