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

H. *_*her 33 linq entity-framework entity-framework-4

我使用实体框架4,我与"级联删除"设置有父子关系.所以当我调用SaveChanges()时,当我从父母中删除孩子时,我会期望删除孩子.

        cuRepository.Attach(_controlUnit);
        foreach (var recipe in recipes) {
            _controlUnit.Recipes.Remove(recipe);
            //repository.DeleteObject(recipe);
        }
Run Code Online (Sandbox Code Playgroud)

相反,我得到一个错误:

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

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

Amy*_*y B 28

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

  • ...所以,如果这是正确的答案,使用了什么代码来实际删除关系? (2认同)
  • @ Ek0nomik他说:repository.DeleteObject(recipe); (2认同)

Chr*_*ris 26

http://weblogs.asp.net/zeeshanhirani/archive/2010/07/23/removing-entity-from-a-related-collection.aspx确切地解释了你的遭遇.


假设您有类设计,如下所示:

样本类设计

实体框架将生成所需的外键列并NOT NULL为它们添加约束,因为所有配方将始终与一个ControlUnit关联.

因此,在运行时,您将拥有类似于以下布局的对象:

运行时的对象图

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

已删除关系的对象

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

这也解释了当您取消注释删除实体的行时它的工作原理:实体与数据库及其关系一起被删除,因此没有违反约束,因此没有例外.

"但我开始ON DELETE CASCADE关系......"

是的,但这仅在删除对象时触发,而不是在删除关系时触发.使用ON DELETE CASCADEset,这应该工作:

controlUnitRepository.DeleteObject(_controlUnit);
// deletes the ControlUnit and all associated Recipe entities
Run Code Online (Sandbox Code Playgroud)

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

更新的类图与组成

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


vit*_*ore 11

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


Gra*_*ler 6

如果您将child和parent之间的关系设置为标识关系,则可以从集合中删除子实体.您需要将子密钥作为包含父级主ID的组合密钥.那样EF知道它需要移除孩子.

识别关系基本上说如果父母不存在那么孩子没有意义.这意味着EF知道在删除关系时删除子项是安全的.

请参阅此问题识别关系并插入子实体会导致"无法为表中的标识列插入显式值",这一个是否可以从集合中删除子项并解决SaveChanges上的问题?