2010-03-31 85 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