entity framework中的批量删除
我想使用linq批量删除表中的记录。 有一篇post描述了如何做到这一点: LINQ to Entities中的批量删除
var query = from c in ctx.Customers where c.SalesPerson.Email == "..." select c; query.Delete();
但是我的var变量中不存在“删除”function。
此外,我的上下文中不存在“SubmitChanges”function。
有一个有趣的NuGet包, 可以让你进行批量删除和更新 :
entity framework中目前不支持批量删除。 它实际上是在codeplex上讨论的function之一,现在EF是开源的。
EntityFramework.Extended
提供批量删除支持(你可以在nuget中找到它)但是我的经验是它有一些性能问题。
此代码为任何DbContext添加了一个简单的扩展方法,该方法将批量删除您提供的entity framework查询中引用的任何表中的所有数据。 它的工作原理是简单地提取查询中涉及的所有表名,并尝试通过发出“DELETE FROM tablename”SQL查询来删除数据,这在大多数类型的数据库中都很常见。
要使用,只需执行以下操作:
myContext.BulkDelete(x => x.Things);
这将删除链接到Things实体商店的表中的所有内容。
代码:
using System.Linq; using System.Text.RegularExpressions; namespace System.Data.Entity { public static class DbContextExtensions { /// /// Efficiently deletes all data from any database tables used by the specified entity framework query. /// /// The DbContext Type on which to perform the delete. /// The Entity Type to which the query resolves. /// The DbContext on which to perform the delete. /// The query that references the tables you want to delete. public static void BulkDelete(this TContext ctx, Func> deleteQuery) where TContext : DbContext { var findTables = new Regex(@"(?:FROM|JOIN)\s+(\[\w+\]\.\[\w+\])\s+AS"); var qry = deleteQuery(ctx).ToString(); // Get list of all tables mentioned in the query var tables = findTables.Matches(qry).Cast().Select(m => m.Result("$1")).Distinct().ToList(); // Loop through all the tables, attempting to delete each one in turn var max = 30; var exception = (Exception)null; while (tables.Any() && max-- > 0) { // Get the next table var table = tables.First(); try { // Attempt the delete ctx.Database.ExecuteSqlCommand(string.Format("DELETE FROM {0}", table)); // Success, so remove table from the list tables.Remove(table); } catch (Exception ex) { // Error, probably due to dependent constraint, save exception for later if needed. exception = ex; // Push the table to the back of the queue tables.Remove(table); tables.Add(table); } } // Error error has occurred, and cannot be resolved by deleting in a different // order, then rethrow the exception and give up. if (max <= 0 && exception != null) throw exception; } } }
我这样做似乎工作得很好。 请知道是否有任何理由说这是不好的做法。
var customersToDelete = await ctx.Customers.Where(c => c.Email == "...").ToListAsync(); foreach (var customerToDelete in customersToDelete) { ctx.Customers.Remove(customerToDelete); } await ctx.SaveChangesAsync();