EF 4:从集合中删除子对象不会删除它 - 为什么?

时间:2010-03-31 16:34:25

标签: linq entity-framework entity-framework-4

我使用Entity Framework 4,并且我与“Cascade Delete”集具有父子关系。 所以当我调用SaveChanges()时,当我从父母中删除孩子时,我会期望删除孩子。

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

相反,我得到一个错误:

  

System.InvalidOperationException发生Message =操作   失败:因为一个或多个关系无法改变   外键属性是不可为空的。当对a进行更改时   关系,相关的外键属性设置为空值。   如果外键不支持空值,则为新关系   必须定义外键属性必须另外分配   必须删除非空值或不相关的对象。

当我明确删除子项时(请参阅注释行),一切都很好。我错过了什么?

5 个答案:

答案 0 :(得分:28)

您没有使用remove语句删除该对象。相反,您试图更改记录并使其成为孤立(通过将外键设置为null)。数据库在该列上具有非空约束,并阻止您这样做。

答案 1 :(得分: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

现在您的代码发挥作用并删除了Recipe对象与其ControlUnit之间的关系:

objects with deleted relationships

此时尝试保存,数据库没有要放入外键NOT NULL列的ControlUnit ID。当前对象状态违反了上面的类图,并且无法保存到在假设每个Recipe与一个ControlUnit关联的情况下生成的数据库布局中。这就是数据库拒绝保存更改并且您看到异常的原因。

这也解释了当你取消注释删除实体的行时它的工作原理:实体从数据库中删除了它的关系,因此不会违反任何约束,因此没有例外。

“但我在关系上设置了ON DELETE CASCADE ......”

是的,但这仅在删除对象时触发,而不是在删除关系时触发。设置ON DELETE CASCADE后,这应该有效:

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

如果您想在删除与ControlUnit的关系时触发删除配方实体,那么您的关系不应该只是一个简单的关联,而应该是一个组合:

updated class diagram with composition

EF本身不支持此功能,但您可以使用标识关系来模拟行为。一旦实体处于与父实体的识别关系中并且该关系被移除,该实体也将被移除。从一开始,这似乎是你的意图。有关识别关系的更多信息,请参阅Implementing identifying relationships with EF4我在哪里实现了与EF4的识别关系,并链接到更多阅读材料。

答案 2 :(得分:10)

在循环中添加context.DeleteObject(recipe)

答案 3 :(得分:6)

如果您将child和parent之间的关系设置为标识关系,则可以从集合中删除子实体。您需要将子密钥设为包含父级主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?

答案 4 :(得分:3)

我使用此扩展名是为了不在DAL中添加方法只是为了删除实体(代码取自http://blogs.msdn.com/b/alexj/archive/2009/06/08/tip-24-how-to-get-the-objectcontext-from-an-entity.aspx):

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)这样的实体。

使用扩展程序的限制条件是:
- 实体必须有关系;
- 实体必须附加到ObjectContext。

相关问题