27

I am trying to delete multiple rows from a table.

In regular SQL Server, this would be simple as this:

DELETE FROM Table
WHERE
    Table.Column = 'SomeRandomValue'
    AND Table.Column2 = 'AnotherRandomValue'

In Entity Framework 6, they have introduced RemoveRange() method.
However, when I use it, rather than deleting rows using the where clauses that I provided, Entity Framework queries the database to get all rows that match the where clauses and delete them one by one using their primary keys.

Is this the current limitation of EntityFramework? Or am I using RemoveRange() wrong?

Following is how I am using RemoveRange():

db.Tables.RemoveRange(
    db.Tables
        .Where(_ => _.Column == 'SomeRandomValue'
            && _.Column2 == 'AnotherRandomValue')
);
Peter Han
  • 547
  • 1
  • 6
  • 13
  • Is Tables the name of your repository? – Jeremy Holovacs Mar 03 '14 at 20:47
  • 3
    [EntityFramework.Extended](https://github.com/loresoft/EntityFramework.Extended) features a [batch delete](https://github.com/loresoft/EntityFramework.Extended/wiki/Batch-Update-and-Delete) – crthompson Mar 03 '14 at 20:51
  • 1
    check this out: http://stackoverflow.com/questions/2519866/how-do-i-delete-multiple-rows-in-entity-framework-without-foreach – Cristi Pufu Mar 03 '14 at 20:59
  • @JeremyHolovacs: db is my DbContext and Table is the name of the database table. I am trying to create the simplest code to demonstrate the problem that I am experiencing. – Peter Han Mar 03 '14 at 22:20
  • @CristiPufu: That question is what directed me to `RemoveRange()`. – Peter Han Mar 03 '14 at 22:20
  • then you should check out `EntityFramework.Extended` as it appears that entity framework has its limitations – Cristi Pufu Mar 04 '14 at 00:14
  • 1
    @CristiPufu & @paqogomez: Yeah, I am checking out EntityFramework.Extended. It is just unfortunate that MS built `RemoveRange()` functions but it still does looping. – Peter Han Mar 04 '14 at 23:24
  • 'It is just unfortunate that MS built RemoveRange() functions but it still does looping.' Yep, so ridiculous. This kind of oh so basic limitation keeps me looking out for better ORMs. – Nicholas Petersen May 25 '14 at 06:02
  • 1
    I believe that RemoveRange was a community contribution that is slightly faster than looping through a bunch of entities yourself, but it's still deleting them one by one. There are no built-in support for batch delete in EF (other than running your own SQL) – ESG Mar 15 '15 at 23:12
  • @TheVedge: That totally makes sense. Thanks for shedding light on that. I will just have to wait and see if they add it in EF7. – Peter Han Mar 18 '15 at 03:49
  • @ESG, that makes me very sad. Looks like I'm still stuck using in-line SQL for deletions until MS can make EF do this basic stuff. – Jacob Stamm Sep 23 '15 at 20:11
  • @JacobStamm I've been using the EntityFramework extension suggested by paqogomez recently. Works marvelously. – ESG Sep 24 '15 at 01:09
  • @PeterHan btw, this usage of `_` for lambda parameter name is normally "forbidden". Its normally only used for when it is not used after the lambda (=>) itself. – Mafii Apr 26 '16 at 13:13
  • Why don't you just have an adapter to the database and just send the appropriate delete command like in your example? – Shar1er80 Mar 15 '15 at 20:07
  • I can. But that means I have to write the basic DELETE statement myself. That completely defeats the point of having an ORM. Also, what if I want a complex WHERE clause? By the time I have a super generic enough adapter that can handle bunch of different WHERE clause, I basically have built the ORM myself. – Peter Han Mar 18 '15 at 03:48

7 Answers7

7

I think we reached here a limitation of EF. Sometimes you just have to use ExecuteSqlCommand to stay performant.

Adi
  • 5,113
  • 6
  • 46
  • 59
5

What you are looking for is a Batch Delete Library which deletes multiple records in a database from a LINQ Query without loading entities.

Multiple libraries supporting this feature exist.

You can find the list here: Entity Framework Batch Delete Library

Disclaimer: I'm the owner of the project Entity Framework Plus

// using Z.EntityFramework.Plus; // Don't forget to include this.

// DELETE directly in SQL (without loading entities)
db.Tables.Where(_ => _.Column == 'SomeRandomValue'
                     && _.Column2 == 'AnotherRandomValue')
         .Delete();

// DELETE using a BatchSize      
db.Tables.Where(_ => _.Column == 'SomeRandomValue'
                     && _.Column2 == 'AnotherRandomValue')
         .Delete(x => x.BatchSize = 1000);

Wiki: EF+ Batch Delete

Jonathan Magnan
  • 10,874
  • 2
  • 38
  • 60
1

It's a bit broken, try

db.Tables.RemoveRange(
    db.Tables
        .Where(_ => _.Column == 'SomeRandomValue'
            && _.Column2 == 'AnotherRandomeValue').AsEnumerable().ToList()
);
db.SaveChanges();
TFD
  • 23,890
  • 2
  • 34
  • 51
  • 1
    Sorry, I still get the same result with this code. Entity Framework executes the inner query then loops through each row and deletes them. – Peter Han Mar 03 '14 at 22:25
0
var db1 =  db.Tables
        .Where(_ => _.Column == 'SomeRandomValue'
            && _.Column2 == 'AnotherRandomeValue').AsEnumerable().ToList();
db.Tables.RemoveRange(db1);
db.SaveChanges();

Use an Variable to Store Removable list and pass it to RemoveRange().

I Usually do like this, and That's Work. Hope This also work in your case.

AKASH
  • 416
  • 1
  • 7
  • 19
  • 2
    Sorry, I still get the same result with this code. Entity Framework executes the inner query then loops through each row and deletes them. – Peter Han Apr 20 '15 at 19:43
  • If your table have foreign key, Specify in model using [Foreign] Attribute and use virtual – AKASH Apr 23 '15 at 14:34
0

Step back and think. Do you really want to download the records from the database in order to delete them? Just because you can doesn't make it a good idea.

Perhaps you could consider deleting the items from the database with a stored procedure? EF also allows to do that...

Crono
  • 10,211
  • 6
  • 43
  • 75
  • 1
    I agree that stored procedure in this situation is the better solution. However, I also believe that is a short coming of EF. Deleting bunch of rows that match a certain criteria is basic CRUD. The fact that a stored procedure to do this better defeats the point of using an ORM. – Peter Han Apr 20 '15 at 19:29
  • There is something known as the "orm impedance mismatch", what it states in a nutshell is that databases are designed for - speed or CRUD operations - efficient size on disk - referential integrity and not just to keep data available after reboot or making sharing of data across system boundaries possible. – Walter Verhoeven Aug 16 '15 at 08:04
0

I'm dealing with this myself, and agree with Adi - just use sql.

I'm cleaning up old rows in a log table, and EF RemoveRange took 3 minutes to do the same thing this did in 3 seconds:

DELETE FROM LogEntries WHERE DATEDIFF(day, GETDATE(), Date) < -6

Date is the name of the column containing the date. To make it correct, use a parameter, of course, like this:

  context.Database.ExecuteSqlCommand
      ("DELETE FROM  LogEntries WHERE DATEDIFF(day, GETDATE(), Date) < @DaysOld", new System.Data.SqlClient.SqlParameter(
                        "DaysOld", - Settings.DaysToKeepDBLogEntries));

Note that there are a lot of rows involved in my case. When I started the project and didn't have a lot of data, RemoveRange worked fine.

0

I have met this problem as well, this is my workaround with a library called entityframework.extended by LoreSoft (which you can get it from nuget package manager):

1.You first query them your list. 2.Then use .Delete(), which is a function from .extended library.

var removeList = db.table.Where(_ => _.Column == 'SomeRandomValue'&& _.Column2 == 'AnotherRandomValue')        
removeList .Delete();

Note: According to Entity Framework EF extended, as of the time writing, this entityframework.extended is deprecated. Therefore one might need to consider entityframework plus library. While i have not tested on the plus extension, but i can confirmed working it works using .extended library.

csamleong
  • 769
  • 1
  • 11
  • 24
  • You should probably explain `.Delete()` comes from an external library and is not part of entity framework – Ashley Medway Mar 09 '19 at 10:06
  • 1
    @csamleong, there are multiple comments and answers in this question that points to Entity Framework Extended. The goal of my question was to see if there is a vanilla EF way of doing this. Based on the answers I got, there isn't. While I have just given up on this issue and moved on, it's nice to see this question is still bothering a lot of people. Hopefully EF will figure something out soon or adopt EF extended into its own offering. – Peter Han Mar 10 '19 at 08:17