Is there any way to bulk-delete a bunch of objects matching a given query in LINQ or LINQ-to-Entities? The only references that I can find are outdated, and it seems silly to iterate over and manually delete all objects I wish to remove.
-
Does this answer your question? [How do I delete multiple rows in Entity Framework (without foreach)](https://stackoverflow.com/questions/2519866/how-do-i-delete-multiple-rows-in-entity-framework-without-foreach) – Michael Freidgeim May 29 '22 at 08:14
14 Answers
A while back I wrote a 4 part blog series (Parts 1, 2, 3 and 4) covering doing bulk updates (with one command) in the Entity Framework.
While the focus of that series was update, you could definitely use the principles involved to do delete.
So you should be able to write something like this:
var query = from c in ctx.Customers
where c.SalesPerson.Email == "..."
select c;
query.Delete();
All you need to do is implement the Delete() extension method. See the post series for hints on how...
Hope this helps

- 20,874
- 3
- 50
- 49
-
Excellent series. Writing a Delete() extension method based on this will be trivial. – Benjamin Pollack May 15 '09 at 18:11
-
20
-
1A bunch of extension methods (including a batch delete) can be found here: https://github.com/loresoft/EntityFramework.Extended – Soliah Apr 19 '12 at 05:49
-
1Beware https://github.com/loresoft/EntityFramework.Extended has a dependency on EF5, if you use Nuget Package manager Console to install it, it will without asking you install EF5 – Paul Zahra Oct 02 '12 at 15:29
-
1It doesn't really help - I would like to see a working example of a Delete command and not "guess" how to implement my own in production code and possibly screw something up. -1 – marknuzz Feb 05 '13 at 20:01
-
31Hm...so the answer to the question is to redirect to 4 blog posts instead of presenting the specific answer to the audience. – DeepSpace101 Apr 13 '13 at 19:02
-
The nuget package of loresoft is not working well on several cases and does not seem to be maintained anymore. I ended up removing it of my projects and replace it by use of stored procedures. – Micaël Félix Oct 06 '15 at 07:35
-
2
using (var context = new DatabaseEntities())
{
// delete existing records
context.ExecuteStoreCommand("DELETE FROM YOURTABLE WHERE CustomerID = {0}", customerId);
}

- 83,883
- 25
- 248
- 179
-
4+1 - Nice to see a code example of how to do execute SQL code using EF – Carlos P Feb 23 '12 at 13:37
-
2I realize this is probably the only way to do this, short of creating a stored procedure, but this feels like cheating =). Now that i'm using this, i'm tempted to use it in several other places to cicumvent EF's quirkiness lol - such as complex left joins and group bys..... :) – Losbear Dec 19 '12 at 15:04
-
+!... when using a DB, you'll find that the tool you want is a screwdriver.. EF is just another hammer. – gbjbaanb Aug 12 '13 at 14:48
-
3Slight downside: you now have a database command that is disconnected from the development environment. It's not strongly typed, so a change to the database for columns in this SQL **will not be highlighted** in Visual Studio – Ian Apr 27 '16 at 15:49
The question is an old one (from before EF5 existed). For anyone who's using EF5, EntityFramework.Extended does this in a snap.

- 36,951
- 69
- 249
- 387
The Answers I'm seeing here are Linq to Sql
DeleteAllOnSubmit is part of System.Data.Linq and ITable which is Linq to Sql
This can't be done with Entity Framework.
Having said all of that I don't have a solution yet but will post back when I do

- 1,014
- 9
- 11
For those who use EF6 and want to execute row SQL query for deletion:
using (var context = new DatabaseEntities())
{
// delete existing records
context.Database.ExecuteSqlCommand("DELETE FROM YOURTABLE WHERE CustomerID = @id", idParameter);
}

- 11,948
- 11
- 47
- 68
-
1This worked for me in EF 5 but I had to use @p0 for the param. What's nice is that it provides type safe param checking in the generated sql: so in EF5, this would work: context.Database.ExecuteSqlCommand("DELETE FROM YOURTABLE WHERE CustomerID = @p0", idParameter); \@p1 for next param, etc... – Nathan Prather Nov 07 '14 at 17:55
-
YOURTABLE can be obtained like this: https://stackoverflow.com/a/45671666/1016343 With that you can write a function that takes the table as a type parameter. Then you will have a generic bulk operation for deleting tables. – Matt Mar 02 '21 at 09:37
RemoveRange was introduced in EF6, it can remove a list of objects. Super easy.
var origins= (from po in db.PermitOrigins where po.PermitID == thisPermit.PermitID select po).ToList();
db.PermitOrigins.RemoveRange(origins);
db.SaveChanges();

- 1,085
- 2
- 16
- 40
-
1While this code snippet may solve the question, [including an explanation](http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – DimaSan Feb 27 '17 at 17:36
I know of DeleteAllOnSubmit method of any data context which will delete all the records in query. There must be some optimization underlying since a lot of objects are being deleted. I am not sure though.

- 19,486
- 24
- 91
- 127
-
4There actually is not any optimization being performed. The generated SQL enumerates all objects that match your query, then manually iterates over them to delete them. Granted, the iteration happens in the DB, rather than in your code, but you're still needlessly building a result set merely to delete its contents--still far worse than a simple "DELETE FROM table WHERE foo = bar", which builds no result set and covers the table only once. – Benjamin Pollack May 15 '09 at 15:28
I'm not sure how efficient it would be, but you could try something like this:
// 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();

- 12,325
- 3
- 42
- 54
-
2That still ends up iterating over all elements that match the query; it merely does so on the DB, rather than in your code. More efficient, but still far from an ideal solution. – Benjamin Pollack May 15 '09 at 15:26
-
3The only other way I could think to do it, then, would be to do myDataContext.ExecuteCommand("DELETE ...");. Far from ideal, also, but it would work. – Scott Arrington May 15 '09 at 15:31
-
The major advantage of this method is that errors due to schema changes can be caught at at compile time, plus you get IntelliSense & Debugging support. However, the performance is abysmal. All records are fetched, then deleted one by one with full data comparison to verify that the correct record is being deleted. This method may be suitable for unit tests or other infrequently called pieces of code where code maintainability is more important than performance. – humbads Jul 24 '21 at 17:28
Deleting data via the Entity Framework relies on using the DeleteObject method. You can call this method on the EntityCollection for the entity class you want to delete or on the derived ObjectContext. Here is a simple example:
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();

- 99
- 4
In this example I get the records to delete, and one by one attach them to the results set then request to have them removed. Then I have 1 save changes.
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();
}
}

- 6,242
- 6
- 43
- 58
context.Entity.Where(p => p.col== id)
.ToList().ForEach(p => db.Entity.DeleteObject(p));
these is fastest method to delete record from DB using EF

- 840
- 7
- 13
YOu could write a stored proc that does the delete and call it from LINQ. A set-based delete is likely faster overall but if it affects too many records you could cause locking issues and you might need a hybrid of looping through sets of records (maybe 2000 at a time, size depends on your database design but 2000 is a starting place if you find the set-based delte takes so long it is affecting other use of the table) to do the delete.

- 94,695
- 15
- 113
- 186
I'd do something like:
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();
}
}
I don't think there is a way to do it without a loop since Entity Framework works with Entities and most of the time, these means collection of objects.

- 786
- 1
- 7
- 18
-
-
-
2@GJennyRamirez also in your example you are savingChanges multiple times which I think you can pull that out side the foreach loop and execute once – Demodave Feb 11 '15 at 16:52
There is not bulk operation implemented in the current EF.
It is just the way it was designed by the entity framework team. The decompiler shows clearly what EF is doing internally:
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);
}
}
As you can see, internally the EF loops through all elements of the table - materialized in memory by calling .ToList()
.
If you still want to do it with the possibilities coming with EF out of the box, and not submit a SQL command, you can still make your life easier with a little helper method. The syntax
ctx.Table1.DeleteAllOnSubmit(ctx.Table1);
ctx.Table2.DeleteAllOnSubmit(ctx.Table2);
ctx.Table3.DeleteAllOnSubmit(ctx.Table3);
ctx.SubmitChanges();
doesn't look very nice in my opinion.
Here's an example I wrote in LinqPad, that simplifies it a bit:
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();
}
If you're doing testing and need to delete a lot of tables, then this syntax is much easier to handle. In other words, this is some syntactic sugar for your convenience. But keep in mind that EF still loops through all objects internally and in memory, which can be very inefficient if it is much data.

- 25,467
- 18
- 120
- 187
-
This is LINQ-to-SQL, an error often made when working with Linqpad. – Gert Arnold Feb 02 '21 at 15:35
-
That said, you only propose a little method that gives some syntactic sugar while not addressing the issue. Not really relevant IMO. – Gert Arnold Feb 02 '21 at 15:44
-
@GertArnold - That critic goes mainly to the entity framework team which has not provided such a function to really bulk delete data, as I pointed out with the disassembled code. But indeed we're looking for a solution here. The little function I wrote would be more helpful if I could determine the name of the table as string to call a SQL delete statement. Do you have an idea Gert, how that can be obtained? Then I could change the function and it would really do a bulk operation by using SQL DELETE. – Matt Feb 03 '21 at 07:25
-
That's all beside the point. EF doesn't provide bulk delete, period. There are many ways to create code that carries out point deletes just a bit easier. All irrelevant. Other answerers didn't get this either. – Gert Arnold Feb 03 '21 at 08:15
-
-
Bringing us back to my first comment. Don't waste your energy proving that EF's version `RemoveRange` doesn't carry out bulk delete either. – Gert Arnold Feb 03 '21 at 08:43
-
@GertArnold - You are right, and I thank you for that. I hope some day EF will have real optimized bulk operations ... – Matt Feb 03 '21 at 12:41