在LINQ to Entities中批量删除

时间:2009-05-15 15:02:40

标签: c# database linq entity-framework linq-to-entities

有没有办法在LINQ或LINQ-to-Entities中批量删除与给定查询匹配的一堆对象?我能找到的唯一引用已经过时了,迭代并手动删除我想删除的所有对象似乎很愚蠢。

14 个答案:

答案 0 :(得分:55)

前段时间我写了4部分博客系列(部件1234),其中包括批量更新(使用一个命令)实体框架。

虽然该系列的重点是更新,但你绝对可以使用所涉及的原则进行删除。

所以你应该写下这样的东西:

var query = from c in ctx.Customers
            where c.SalesPerson.Email == "..."
            select c;

query.Delete();

您需要做的就是实现Delete()扩展方法。有关如何...的提示,请参阅帖子系列。

希望这有帮助

答案 1 :(得分:40)

    using (var context = new DatabaseEntities())
    {
        // delete existing records
        context.ExecuteStoreCommand("DELETE FROM YOURTABLE WHERE CustomerID = {0}", customerId);
    }

答案 2 :(得分:29)

问题是旧问题(从EF5之前就存在)。对于使用EF5的任何人,EntityFramework.Extended都可以轻松完成。

答案 3 :(得分:6)

我在这里看到的答案是Linq to Sql

DeleteAllOnSubmit是System.Data.Linq和ITable的一部分,它是Linq to Sql

使用Entity Framework无法做到这一点。

说完所有这些我还没有解决方案,但会在我做的时候回复

答案 4 :(得分:4)

对于那些使用EF6并希望执行行SQL查询以进行删除的人:

using (var context = new DatabaseEntities())
{
    // delete existing records
    context.Database.ExecuteSqlCommand("DELETE FROM YOURTABLE WHERE CustomerID = @id", idParameter);
}

答案 5 :(得分:2)

我知道任何数据上下文的DeleteAllOnSubmit方法,它会删除查询中的所有记录。由于删除了很多对象,因此必须有一些优化。我不确定。

答案 6 :(得分:2)

我不确定它会有多高效,但你可以尝试这样的事情:

// deletes all "People" with the name "Joe"
var mypeople = from p in myDataContext.People
               where p.Name == "Joe";
               select p;
myDataContext.People.DeleteAllOnSubmit(mypeople);
myDataContext.SubmitChanges();

答案 7 :(得分:1)

你可以写一个执行删除的存储过程并从LINQ调用它。基于集合的删除总体上可能更快,但如果它影响太多记录,则可能导致锁定问题,并且您可能需要循环记录集合(可能一次20​​00个,大小取决于您的数据库设计,但2000是一个如果您发现基于集合的delte需要很长时间才会影响表的其他用途,从而进行删除。

答案 8 :(得分:1)

通过Entity Framework删除数据依赖于使用DeleteObject方法。您可以在EntityCollection上为要删除的实体类或派生的ObjectContext调用此方法。这是一个简单的例子:

NorthwindEntities db = new NorthwindEntities();

IEnumerable<Order_Detail> ods = from o in db.Order_Details
                                where o.OrderID == 12345                                    
                                select o;

foreach (Order_Detail od in ods) 
    db.Order_Details.DeleteObject(od);

db.SaveChanges();

答案 9 :(得分:1)

我做的事情如下:

var recordsToDelete = (from c in db.Candidates_T where c.MyField == null select c).ToList<Candidates_T>();
if(recordsToDelete.Count > 0)
{
    foreach(var record in recordsToDelete)
    {
        db.Candidate_T.DeleteObject(record);
        db.SaveChanges();
    }
}   

我认为没有循环可以做到这一点,因为实体框架与实体一起工作,大多数时候,这意味着对象的集合。

答案 10 :(得分:1)

在此示例中,我获取要删除的记录,并逐个将它们附加到结果集,然后请求删除它们。然后我有1个保存更改。

    using (BillingDB db = new BillingDB())
    {
      var recordsToDelete = (from i in db.sales_order_item
                  where i.sales_order_id == shoppingCartId
                  select i).ToList<sales_order_item>();

      if(recordsToDelete.Count > 0)
      {
        foreach (var deleteSalesOrderItem in recordsToDelete)
        {                  
            db.sales_order_item.Attach(deleteSalesOrderItem);
            db.sales_order_item.Remove(deleteSalesOrderItem);                  
        }
        db.SaveChanges();
      } 
    }

答案 11 :(得分:1)

 context.Entity.Where(p => p.col== id)
               .ToList().ForEach(p => db.Entity.DeleteObject(p));

这是使用EF

从DB中删除记录的最快方法

答案 12 :(得分:1)

在EF6中引入了RemoveRange,它可以删除对象列表。超级容易。

var origins= (from po in db.PermitOrigins where po.PermitID == thisPermit.PermitID select po).ToList();
db.PermitOrigins.RemoveRange(origins);
db.SaveChanges();

答案 13 :(得分:0)

当前 EF 中没有实现批量操作。

这正是实体框架团队设计的方式。反编译器清楚地显示了 EF 在内部做什么:

public void DeleteAllOnSubmit<TSubEntity>(IEnumerable<TSubEntity> entities) 
where TSubEntity : TEntity
{
    if (entities == null)
    {
        throw Error.ArgumentNull("entities");
    }
    CheckReadOnly();
    context.CheckNotInSubmitChanges();
    context.VerifyTrackingEnabled();
    foreach (TSubEntity item in entities.ToList())
    {
        TEntity entity = (TEntity)(object)item;
        DeleteOnSubmit(entity);
    }
}

如您所见,EF 在内部循环遍历表的所有元素 - 通过调用 .ToList() 在内存中具体化。

如果您仍然想使用 EF 开箱即用的可能性来完成它,而不是提交 SQL 命令,您仍然可以通过一个小助手方法让您的生活更轻松。 语法

ctx.Table1.DeleteAllOnSubmit(ctx.Table1);
ctx.Table2.DeleteAllOnSubmit(ctx.Table2);
ctx.Table3.DeleteAllOnSubmit(ctx.Table3);
ctx.SubmitChanges();

我觉得不太好看。

这是我在 LinqPad 中写的一个例子,它简化了一点:

void Main()
{
    var ctx = this;

    void DeleteTable<T>(System.Data.Linq.Table<T> tbl, bool submitChanges = false)
    where T : class
    {
        tbl.DeleteAllOnSubmit(tbl);
        if (submitChanges) ctx.SubmitChanges();
    }
    
    DeleteTable(ctx.Table1);
    DeleteTable(ctx.Table2);
    DeleteTable(ctx.Table3);
        
    ctx.SubmitChanges();
}

如果你在做测试并且需要删除很多表,那么这个语法更容易处理。换句话说,这是一些为您提供方便的语法糖。但请记住,EF 仍会在内部和内存中循环遍历所有对象,如果数据量很大,这可能会非常低效。