18

我正在使用EF4 CTP 5,CodeFirst。實體框架:使用CodeFirst設置刪除規則

請第一次看到我的課:

public class Guest 
{ 
     [Key] 
     public Guid GuestID { get; set; } 

     public Language PreferredLanguage { get; set; } 
     public Guid? LanguageID { get; set; } 
} 

public class Language 
{ 
     [Key] 
     public Guid LanguageID { get; set; } 

     [Required(ErrorMessage = "Enter language name")] 
     [StringLength(50, ErrorMessage = "Language name is too long")] 
     public string LanguageName { get; set; } // in origine language 
} 

我的目標是設置一定的「刪除規則」,爲客戶語言的關係。當一種語言被刪除時,我不希望刪除相應的guest(所以NO級聯刪除)。相反,我希望客人的LanguageID爲「設置NULL」。

我希望流利的API在這裏支持我。但除了.WillCascadeOnDelete(bool)之外,我找不到任何有用的東西,它不提供我需要的選項。我錯過了什麼嗎?或者這只是沒有在CTP 5中實現?

感謝您的幫助!

回答

32

什麼你正在尋找可以通過GuestLanguage實體之間建立一個可選協會來實現:

protected override void OnModelCreating(ModelBuilder modelBuilder) 
{ 
    modelBuilder.Entity<Guest>() 
       .HasOptional(p => p.PreferredLanguage) 
       .WithMany() 
       .HasForeignKey(p => p.LanguageID); 
} 

單元測試:

using (var context = new Context()) 
{ 
    var language = new Language() 
    { 
     LanguageName = "en" 
    }; 
    var guest = new Guest() 
    { 
     PreferredLanguage = language 
    }; 
    context.Guests.Add(guest); 
    context.SaveChanges(); 

    context.Languages.Remove(language); 
    context.SaveChanges(); 
} 

其結果是,我們將最終產生一個guest記錄,其中包含LanguageID FK列的數據庫空值。


更新:

首先讓我們來看看爲什麼上面的單元測試通過查看SQL事件探查成功。以下顯示了跟蹤撥打第二的SaveChanges()方法後右:

enter image description here enter image description here

因此,大家可以看到,EF是足夠聰明,通過設置其LanguageID爲null,則首先更新客戶記錄提交刪除語句以刪除在設置可選關聯時作爲默認EF行爲的語言記錄。所以EF在應用程序方面已經考慮到了這一點,當然如果你嘗試像你之前提到的那樣手動刪除SQL Server內部的語言記錄,那麼你會從DBMS中得到一個錯誤。

但是,這個故事還有更多。考慮下面的單元測試:

using (var context = new Context()) 
{ 
    var language = new Language() { LanguageName = "en" }; 
    var guest = new Guest() { PreferredLanguage = language }; 
    context.Guests.Add(guest); 
    context.SaveChanges(); 
} 

using (var context = new Context()) 
{ 
    var language = context.Languages.First();   
    context.Languages.Remove(language); 
    context.SaveChanges(); 
}  

這一次失敗,並拋出的SQLException包含試圖手動刪除記錄,你從SQL Server得到了確切的消息。原因在於,在第二次單元測試中,我們沒有在上下文中加載相關guest對象,因此EF不知道它,並且不會像第一個示例中那樣提交必要的更新語句。

回到你的問題,不幸的是EF代碼第一次不允許明確更改刪除關係/更新的規則,但我們總是可以訴諸的SqlCommand方法,你看到this post它的一個例子。在你的情況下,我們可以編碼:

protected override void Seed(Context context) 
{ 
    context.Database.SqlCommand("ALTER TABLE dbo.Guests DROP CONSTRAINT Guest_PreferredLanguage"); 
    context.Database.SqlCommand("ALTER TABLE dbo.Guests ADD CONSTRAINT Guest_PreferredLanguage FOREIGN KEY (LanguageID) REFERENCES dbo.Languages(LanguageID) ON UPDATE NO ACTION ON DELETE SET NULL"); 
} 

這是你在找什麼。通過採用上述種子方法,第二次單元測試也將通過。

希望這有助於
莫爾塔扎

+0

哇! Excxellent答案!我需要看看你的博客! :-) – 2011-04-03 23:10:06

0

實體框架的核心,我做了這樣的事情......

modelBuilder.Entity<Guest>() 
    .HasOne(g => g.Language) 
    .WithMany(l => l.Guests) // I needed a return collection 
    .OnDelete(DeleteBehavior.SetNull);