【问题标题】:EF6 does not mark the entity's state as deleted when remove from collection从集合中删除时,EF6 不会将实体的状态标记为已删除
【发布时间】:2017-06-30 13:09:44
【问题描述】:

我有下面的代码从父母那里删除孩子和孙子

        MyEntities dbContext = new MyEntities();

        var parent = dbContext.Parents
            .Include(x => x.Childrens.Select(y => y.GrandChildrens))
            .Where(x => x.ParentID == 1)
            .SingleOrDefault();

        // get first child
        var child = parent.Childrens.First();

        // remove all grand childrens from child
        var count = child.GrandChildrens.Count;
        for (int i = 0; i < count; i++)
        {
            child.GrandChildrens.Remove(child.GrandChildrens.ElementAt(0));
        }

        // remove child from parent
        parent.Childrens.Remove(child);            

        // save changes
        dbContext.SaveChanges();

以上代码抛出异常

操作失败:无法更改关系,因为 一个或多个外键属性不可为空。当一个 对关系进行更改,相关的外键属性是 设置为空值。如果外键不支持空值, 必须定义一个新的关系,外键属性必须是 分配了另一个非空值,或者不相关的对象必须是 已删除。

在阅读了几篇文章之后,我似乎必须将实体的状态标记为已删除,而不是从集合中删除实体。

        MyEntities dbContext = new MyEntities();

        var parent = dbContext.Parents
            .Include(x => x.Childrens.Select(y => y.GrandChildrens))
            .Where(x => x.ParentID == 1)
            .SingleOrDefault();

        // get first child
        var child = parent.Childrens.First();

        // remove all grand childrens from child
        var count = child.GrandChildrens.Count;
        for (int i = 0; i < count; i++)
        {
            dbContext.Entry<GrandChild>(child.GrandChildrens.ElementAt(0)).State = EntityState.Deleted;
        }

        // remove child from parent
        dbContext.Entry<Child>(child).State = EntityState.Deleted;

        // save changes
        dbContext.SaveChanges();

上面的代码有效

但是我有问题

1> 如何启用级联删除,这样我就不必明确删除 GrandChildrens?我正在使用数据库优先方法。

2> 如果我们将实体添加到集合中并调用 dbContext.SaveChanges() 则 EF 会保存新添加的实体,即使我们没有将实体的状态显式标记为 Added。为什么删除操作不是这样?为什么我们必须将实体的状态显式设置为Deleted

【问题讨论】:

    标签: entity-framework asp.net-mvc-5


    【解决方案1】:

    啊,伙计,我在 ORM 之间跳来跳去的次数太多了……我更喜欢 NHibernate 的其余原因之一是已经有了关于 EF6 中没有的级联删除孤儿的响应,但显然在 EF Core 中可用预计用于 EF7...

    EF6 需要将实体标记为已删除,因为它仍然缺少孤立跟踪的概念。 :(

    一个稍微不那么冗长的变体

       var child = parent.Childrens.First();
    
       child.GrandChidrens.ToList().ForEach(x=>dbContext.Entity(x).State = EntityState.Deleted);
       dbContext.Entity(child).State = EntityState.Deleted;
       parent.Childrens.Remove(child); 
    

    你可以试试 EF Core,虽然它有很多其他的龙...

    【讨论】:

    • 如果存在深度排除,实体应该反向标记为已删除,即我的情况需要从最深到最先删除。但你的回答也对我有用。非常感谢!
    【解决方案2】:
    1. 当您声明ChildrenGrandchildren 之间的外键关系时,您可以设置删除规则。您可以在SQL Management Studio 中进行操作。只需选择级联。现在 SQL Server 会在删除父表中的记录时删除子表中的所有相关记录。

    2. 我只能猜测。如果您不需要删除记录,而只是想打破关系怎么办?你会用什么方法?方法ICollection.Remove 看起来是个不错的选择。所以这只是 EF 作者的选择。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-11
      • 2020-02-08
      相关资源
      最近更新 更多