【问题标题】:How to delete a list of objects in EF6 when the object is detached from the context当对象从上下文中分离时如何删除 EF6 中的对象列表
【发布时间】:2016-03-08 12:58:46
【问题描述】:

好的,我可以像这样删除 EF6 中的单个项目:

public void DeleteUserGroup(MY_GROUPS ug)
{
    using (var context = new MYConn())
    {
        var entry = context.Entry(ug);
        if (entry.State == EntityState.Detached)
        {
            context.MY_GROUPS.Attach(ug);
        }

        context.MY_GROUPS.Remove(ug);
        context.SaveChanges();
    }
}

如果此方法从传递MY_GROUPS 的单个实例更改为List<MY_GROUPS>,我将如何处理删除?

是否有比只做一个foreach 并一次设置一个状态更有效的方法?

更新: 我已经在使用与上述类似的方法,即RemoveRange 方法。 但是我收到一个错误:

无法删除该对象,因为它在 对象状态管理器。

我正在寻找将对象列表附加到上下文以便删除它们的最佳方法。

【问题讨论】:

  • 您的上下文中没有 .RemoveRange 吗?如果我没记错的话,你可以给 RemoveRange 一个你想删除的项目集合..
  • 我这样做并且我正在使用它。但是我收到错误“无法删除该对象,因为在 ObjectStateManager 中找不到它。”

标签: c# entity-framework entity-framework-6


【解决方案1】:

为了能够删除记录,您需要确保您的 ObjectContext 正在跟踪它们。现在你已经分离了对象,你的上下文不知道它们,所以不可能删除它们。删除它们的一种方法是像你说的那样,Attach 你所有的对象到上下文中,然后删除它们。另一种方法是从数据库中获取记录,以便您可以删除它们:

//Find all groups in database with an Id that is in your group collection 'ug'
var groups = context.My_Groups.Where(g => ug.Any(u => u.Id == g.Id));
context.My_Groups.RemoveRange(groups);
context.SaveChanges();

但是,请注意,即使在使用RemoveRange 时,删除命令也会发送到数据库per 您要删除的项目。 RemoveRangeRemove唯一的区别就是第一个只会调用DetectChanges一次,确实可以提升性能。

【讨论】:

  • 不让我的 ObjectContext 跟踪它们是一种不好的做法吗?基本上我有一个类,每个方法都创建(然后处理)上下文。我用那种方法做我需要做的事情,然后按照自己的方式行事。
  • 取决于您如何获得群组。如果您在一种方法中获取某些组,处理上下文,然后将这些具体化组传递给另一种方法以删除它们,则 不好的做法。但是,如果您将组作为 json 结果或来自网站的其他内容返回,那么您显然无能为力。
  • 是的。我有这样做的方法。我的 UI 使用 POCO,在我的中间层中,我将 POCO 映射到数据库表/从数据库表映射。所以我的 EF 类都在创建/处理上下文。我不相信我设置它是最好的,因为我现在不能重用该类中的现有方法。 IE。如果是删除列表,我通常会调用 GetGroupList 方法返回该列表,然后在我的删除方法中删除它们。现在我一半不调用该方法并在我的删除方法中执行所有操作。
【解决方案2】:

遍历您的集合并为每个集合设置 Deleted 状态

groups.ForEach(group => ctx.Entry(group).State = EntityState.Deleted);
ctx.SaveChanges();

【讨论】:

  • IMO,这是处理断开连接的对象上下文的正确方法。
【解决方案3】:

你可以使用RemoveRange:

context.MY_GROUPS.RemoveRange(context.MY_GROUPS.Where(x => x.columnName== "Foo"));

你也可以像这样使用ForEach

context.MY_GROUPS.Where(x => x.columnName == "Foo").ToList().ForEach(context.DeleteObject);
context.SaveChanges();

您也可以使用ObjectContext.ExecuteStoreCommand Method 作为另一种方法来实现此目的。

【讨论】:

  • 我这样做并且我正在使用它。但是我收到错误“无法删除该对象,因为在 ObjectStateManager 中找不到它。”
【解决方案4】:

我发现它对我有用。在调用保存更改之前,我循环执行了此操作。我希望它只创建删除 sql 命令,它确实做到了。

http://www.entityframeworktutorial.net/entityframework6/delete-disconnected-entity-in-entity-framework.aspx

// disconnected entity to be deleted
var student = new Student(){ StudentId = 1 };

using (var context = new SchoolDBEntities())
{
    context.Entry(student).State = System.Data.Entity.EntityState.Deleted;    

    context.SaveChanges();
}  

【讨论】:

    【解决方案5】:

    EntityFramework 6+ 使用 .RemoveRange() 使这变得更容易了。

        public void DeleteUserGroup(List<MY_GROUPS> ug)
        {
            using (var context = new MYConn())
            {
                context.MY_GROUPS.RemoveRange(ug);
                context.SaveChanges();
            }
        }
    

    【讨论】:

    • 我这样做并且我正在使用它。但是我收到错误“无法删除该对象,因为在 ObjectStateManager 中找不到它。”
    • RemoveRange 调用发生错误。我需要将列表附加到上下文中才能删除它们。 (见我上面的单条删除)
    • 我可以遍历列表并设置状态,但我正在寻找一种更有效的方式来处理这种情况。
    • 我也有同样的问题“无法删除该对象,因为它在 ObjectStateManager 中找不到。”当我要借助 RemoveRange() 方法删除对象列表时。
    【解决方案6】:

    使用Alexander Deck 提供的solution,其中品牌是IEnumerable

    context.Brands.RemoveRange(context.Brands.Where(cb => brands.Any(b => b.Id == cb.Id)));
    

    我收到以下错误:

    无法创建“SomeCompany.SomeApp.DB.Entities.Brand”类型的常量值。此上下文仅支持原始类型或枚举类型。

    通过使用AsEnumerable() 扩展方法将品牌DBSet 转换为IEnumerable 解决了这个问题:

    context.Brands.RemoveRange(context.Brands.AsEnumerable().Where(cb => brands.Any(b => b.Id == cb.Id)));
    

    这对我有用。

    【讨论】:

    • 请注意,调用 AsEnumerable() 将从数据库中检索完整的表“Brands”。这可能是可以接受的,但这取决于您的桌子大小......
    • 感谢@GrégoryBourgin 的建议,我一定会明智地使用它
    猜你喜欢
    • 1970-01-01
    • 2021-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-03
    • 2021-04-12
    • 1970-01-01
    相关资源
    最近更新 更多