从集合中删除时,EF6 不会将实体的状态标记为已删除



我有下面的代码可以从父级中删除子孙

        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();

上面的代码抛出异常

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

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

        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> 如何启用级联删除,这样我就不必显式删除孙子?我正在使用数据库优先方法。

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

啊,伙计,我在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,尽管它还有很多其他的龙......

在声明
  1. ChildrenGrandchildren之间的外键关系时,可以设置删除规则。您可以在 SQL Management Studio 中执行此操作。只需选择级联即可。现在,当您删除父表中的记录时,SQL Server 将删除子表中的所有相关记录。

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

最新更新