【发布时间】:2010-10-26 12:49:34
【问题描述】:
有没有办法批量删除与 LINQ 或 LINQ-to-Entities 中的给定查询匹配的一组对象?我能找到的唯一引用已经过时,迭代并手动删除我希望删除的所有对象似乎很愚蠢。
【问题讨论】:
标签: c# database linq entity-framework linq-to-entities
有没有办法批量删除与 LINQ 或 LINQ-to-Entities 中的给定查询匹配的一组对象?我能找到的唯一引用已经过时,迭代并手动删除我希望删除的所有对象似乎很愚蠢。
【问题讨论】:
标签: c# database linq entity-framework linq-to-entities
【讨论】:
using (var context = new DatabaseEntities())
{
// delete existing records
context.ExecuteStoreCommand("DELETE FROM YOURTABLE WHERE CustomerID = {0}", customerId);
}
【讨论】:
这个问题是一个老问题(在 EF5 存在之前)。对于使用 EF5 的任何人,EntityFramework.Extended 可以快速完成此操作。
【讨论】:
我在这里看到的答案是 Linq to Sql
DeleteAllOnSubmit 是 System.Data.Linq 和 ITable 的一部分,它是 Linq to Sql
实体框架无法做到这一点。
说了这么多,我还没有解决方案,但当我有解决方案时会回复
【讨论】:
对于那些使用EF6并希望执行行SQL查询以进行删除的人:
using (var context = new DatabaseEntities())
{
// delete existing records
context.Database.ExecuteSqlCommand("DELETE FROM YOURTABLE WHERE CustomerID = @id", idParameter);
}
【讨论】:
RemoveRange 是在 EF6 中引入的,它可以删除对象列表。超级简单。
var origins= (from po in db.PermitOrigins where po.PermitID == thisPermit.PermitID select po).ToList();
db.PermitOrigins.RemoveRange(origins);
db.SaveChanges();
【讨论】:
我知道任何数据上下文的DeleteAllOnSubmit 方法将删除查询中的所有记录。由于正在删除许多对象,因此必须进行一些优化。不过我不确定。
【讨论】:
我不确定它的效率如何,但您可以尝试以下方法:
// 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();
【讨论】:
你可以编写一个存储过程来执行删除并从 LINQ 调用它。基于集合的删除总体上可能更快,但如果它影响太多记录,您可能会导致锁定问题,并且您可能需要混合循环遍历记录集(一次可能 2000 个,大小取决于您的数据库设计,但 2000 是如果您发现基于集合的删除需要很长时间以影响表的其他使用)来执行删除。
【讨论】:
通过实体框架删除数据依赖于使用 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();
【讨论】:
在本例中,我将要删除的记录一一附加到结果集中,然后请求将其删除。然后我有 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();
}
}
【讨论】:
context.Entity.Where(p => p.col== id)
.ToList().ForEach(p => db.Entity.DeleteObject(p));
这是使用 EF 从数据库中删除记录的最快方法
【讨论】:
我会这样做:
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();
}
}
我认为没有循环可以做到这一点,因为实体框架与实体一起工作,而且大多数时候,这意味着对象的集合。
【讨论】:
当前 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 仍然会在内部和内存中循环遍历所有对象,如果数据量很大,这可能会非常低效。
【讨论】: