2010-03-31 84 views
33

我使用實體框架4,我有「級聯刪除」設置的父子關係。 所以我期望當我從父母刪除一個孩子被刪除時,我打電話SaveChanges()。EF 4:從集合中刪除子對象不會刪除它 - 爲什麼?

 cuRepository.Attach(_controlUnit); 
     foreach (var recipe in recipes) { 
      _controlUnit.Recipes.Remove(recipe); 
      //repository.DeleteObject(recipe); 
     } 

相反,我得到一個錯誤:

System.InvalidOperationException occurred Message=The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.

當我明確地刪除兒童(見註釋行),一切都很好。我錯過了什麼?

+0

今天我有同樣的問題,我相信這是在實體框架設計缺陷。 SQL Server中的表之間的關係聲明「級聯刪除孤兒」,因此應該可以工作。它在NHibernate中的工作方式。幸運的是,您可以按照GraemeMiller的回答和相關問題開展工作。 – 2013-04-22 10:38:04

回答

28

您不是用remove語句刪除對象。相反,您正試圖更改記錄並將其設置爲孤立(通過將外鍵設置爲空)。該數據庫在該列上有一個非空約束,並阻止您這樣做。

+2

...所以如果這是正確的答案什麼代碼被用來實際刪除關係? – 2013-05-15 16:03:44

+2

@ Ek0nomik他說:repository.DeleteObject(recipe); – 2013-05-15 17:10:22

10

添加context.DeleteObject(recipe)循環

26

http://weblogs.asp.net/zeeshanhirani/archive/2010/07/23/removing-entity-from-a-related-collection.aspx解釋到底發生了什麼,以你的內心。


假設你有一個一流的設計是這樣的:

sample class design

實體框架將生成所需的外鍵列,並添加NOT NULL約束他們,因爲所有的食譜總是以完全相同相關一個ControlUnit。

所以在運行時,你將有類似於以下佈局對象:

object diagram at runtime

現在你的代碼進場,並刪除了配方之間的關係的對象和他們的控制單元:

objects with deleted relationships

試圖保存在這個時候,數據庫沒有一個ControlUnit ID放入外鍵NOT NULL列。當前對象狀態違反了上面的類圖,並且無法將其保存到假設每個配方都與一個ControlUnit關聯的情況下生成的數據庫佈局。這就是數據庫拒絕保存更改並看到異常的原因。

這也解釋了爲什麼它在解除刪除實體的行時註釋掉:實體從數據庫及其關係中刪除,因此沒有違反約束,因此沒有例外。

「但我的關係設置ON DELETE CASCADE ...」

是的,但這只是引發了對象的刪除,不上關係的缺失。隨着ON DELETE CASCADE集,這應該工作:

controlUnitRepository.DeleteObject(_controlUnit); 
// deletes the ControlUnit and all associated Recipe entities 

如果要觸發配方實體刪除它們與控制單元關係的缺失,你們的關係不應該是簡單關聯,而是一個組成:

updated class diagram with composition

EF本身不支持此操作,但可以使用標識關係來模擬行爲。一旦實體處於與父實體的識別關係並且該關係被移除,該實體也被移除。看起來這是你一開始的意圖。有關確定關係的更多信息,請參閱Implementing identifying relationships with EF4,其中我實施了與EF4的識別關係並已鏈接到更多閱讀材料。

public static void Delete<T>(this EntityCollection<T> collection, T entityToDelete) where T : EntityObject, IEntityWithRelationships 
{ 
    RelationshipManager relationshipManager = entityToDelete.RelationshipManager; 

    IRelatedEnd relatedEnd = relationshipManager.GetAllRelatedEnds().FirstOrDefault(); 
    if (relatedEnd == null) 
    { 
     throw new Exception("No relationships found for the entity to delete. Entity must have at least one relationship."); 
    } 

    var query = relatedEnd.CreateSourceQuery() as ObjectQuery; 
    if (query == null) 
    { 
     throw new Exception("The entity to delete is detached. Entity must be attached to an ObjectContext."); 
    } 

    query.Context.DeleteObject(entityToDelete); 
    collection.Remove(entityToDelete); 
} 

所以我然後刪除實體像Order.Products.Delete(prod)

6

如果您使子和父母之間的關係成爲識別關係,那麼您可以從集合中刪除子實體。您需要將子項的鍵設置爲包含父項的主ID鍵的組合鍵。這樣EF知道它需要移除孩子。

識別關係基本上說,如果父母不存在,那麼孩子沒有意義。這意味着EF知道在關係被移除時刪除孩子是安全的。

看到這個問題Identifying Relationship and inserting child entities causes "Cannot insert explicit value for identity column in table"而這一次Is it possible to remove child from collection and resolve issues on SaveChanges?

+0

另請參閱http://stackoverflow.com/questions/3710191/implementing-identifying-relationships-with-ef4其中我遇到了這個問題,並解釋瞭如何創建標識關係。還有一個博客文章鏈接詳細解釋了這一點。 – Chris 2012-12-18 12:06:32