I know this is possible in LINQ-to-SQL, and I\'ve seen bits and pieces that lead me to believe it\'s possible in EF. Is there an extension out there that can do something li
In case anyone else is looking for this functionality, I've used some of Ladislav's comments to improve on his example. Like he said, with the original solution, when you call SaveChanges()
, if the context was already tracking one of the entities you deleted it'll call it's own delete. This doesn't modify any records, and EF considers it a concurrency issue and throws an exception. The method below is slower than the original since it has to first query for the items to delete, but it won't write a single delete query for each deleted entity which is the real performance benefit. It detaches all the entities that were queried, so if any of them were already tracked it will know not to delete them anymore.
public static void DeleteBatch(this DbContext context, IQueryable query) where T : LcmpTableBase
{
IEnumerable toDelete = query.ToList();
context.Database.ExecuteSqlCommand(GetDeleteCommand(query));
var toRemove = context.ChangeTracker.Entries().Where(t => t.State == EntityState.Deleted).ToList();
foreach (var t in toRemove)
t.State = EntityState.Detached;
}
I also changed up this part to use a regular expression since I found that there was an undetermined amount of whitespace near the FROM portion. I also left "[Extent1]" in there because the DELETE query written in the original way couldn't handle queries with INNER JOINS:
public static string GetDeleteCommand(this IQueryable clause) where T : class
{
string sql = clause.ToString();
Match match = Regex.Match(sql, @"FROM\s*\[dbo\].", RegexOptions.IgnoreCase);
return string.Format("DELETE [Extent1] {0}", sql.Substring(match.Index));
}