Skip to main content

How To Use The New Bulk Update Feature In EF Core 7

About 3 minC#DotNetArticle(s)blogmilanjovanovic.techcsc#csharpdotnet

How To Use The New Bulk Update Feature In EF Core 7 관련

C# > Article(s)

Article(s)

How To Use The New Bulk Update Feature In EF Core 7
In this week's newsletter, we're going to explore the new ExecuteUpdate and ExecuteDelete methods that were released with EF7. ExecuteUpdate allows us to write a query and run a bulk update operation on the entities matching that query. Similarly, ExecuteDelete allows us to write a query and delete the entities matching that query. We can significantly improve performance using the new methods in some scenarios, and I'm going to show you what those scenarios are.

In this week's newsletter, we're going to explore the new ExecuteUpdate and ExecuteDelete methods that were released with EF7.

ExecuteUpdate allows us to write a query and run a bulk update operation on the entities matching that query.

Similarly, ExecuteDelete allows us to write a query and delete the entities matching that query.

We can significantly improve performance using the new methods in some scenarios, and I'm going to show you what those scenarios are.

Let's dive in.


Updating And Deleting Entities Before EF Core 7

If you want to update a collection of entities before EF7, you need to load the entities into memory using the DatabaseContext.

The EF ChangeTracker will then track any changes made to these entities. When you are ready to commit the changes to the database, you simply call the SaveChanges method.

Here's an example where we load a few notifications, and we want to snooze them so they aren't sent:

var notifications = dbContext
    .Notifications
    .Where(n => !n.Snoozed)
    .ToList();

foreach(var notification in notifications)
{
    notification.Snoozed = true;
}

dbContext.SaveChanges();

EF7 will generate the following SQL statement to update the records in the database:

UPDATE [Notifications] n
SET n.[Snoozed] = TRUE
WHERE n.[Id] = @notificationId_1;

...

UPDATE [Notifications] n
SET n.[Snoozed] = TRUE
WHERE n.[Id] = @notificationId_N;

Notice that for every notification we end up with one SQL UPDATE statement. This won't scale well as the number of notifications increases.


Updating Entities With ExecuteUpdate

With EF7, we now have access to the new ExecuteUdpate method. It also has an asynchronous version - ExecuteUpdateAsync.

How do you use it?

You need to write a query that will select the records you want to update, and then call the ExecuteUpdate method on the resulting IQueryable.

Let's rewrite the previous example using the new approach:

dbContext
    .Notifications
    .Where(n => !n.Snoozed)
    .ExecuteUpdate(s => s.SetProperty(
        n => n.Snoozed,
        n => true));

In the call to ExecuteUpdate we call the SetProperty method to specify which properties we want to update, and what values we want to set. The SetProperty method can be called multiple times, if you need to update more than one property.

In this case, EF7 will generate the following SQL query:

UPDATE n
SET n.[Snoozed] = TRUE
FROM [Notifications] AS n
WHERE n.[Snoozed] = FALSE;

Notice that this time we only have one SQL query being sent to the database. This is a major performance improvement. It can be as much as 10x faster than the old version, from my testing.


Deleting Entities With ExecuteDelete

Let's also see how we can do bulk deletes using the ExecuteDelete and ExecuteDeleteAsync methods.

Again, you have to write a query that will select the records you want to delete, and then call the ExecuteDelete method on the resulting IQueryable.

If you want to delete all snoozed notifications:

dbContext
    .Notifications
    .Where(n => n.Snoozed)
    .ExecuteDelete();

And EF7 will generate the following SQL query:

DELETE FROM n
FROM [Notifications] AS n
WHERE n.[Snoozed] = TRUE;

I think this will be incredibly useful when you want to delete records in the database based on a specific condition.


Transactions, Change Tracking And Query Filters With Bulk Methods

You need to be aware how transactions and change tracking work with the new bulk methods. ExecuteUpdate and ExecuteDelete will immediately go to database, and run the SQL query.

What does this mean for transactions?

If you want to run a bulk method together with other updates applied with SaveChanges, by default they won't run in the same transaction. You need to open an explicit transaction using the DatabaseContext to keep everything consistent.

What does this mean for change tracking?

ExecuteUpdate and ExecuteDelete run directly on the database, without loading any entities into memory. EF7 will not track these entities in the ChangeTracker.

If you have any database interceptors defined, they won't execute after calling one of the bulk update methods. This also means that if you override SaveChanges to add custom behavior, it won't be called.

Do Query Filters still work?

Yes, query filters will be correctly applied when calling ExecuteUpdate or ExecuteDelete.


When Should You Use The New Bulk Methods?

I think this is an excellent new addition to EF7, and it solves a real problem when you need to run a typical UPDATE or DELETE query with a WHERE statement applied.

Previously, you had to write raw SQL and execute it using something like Dapper.

I will likely use this approach when it applies to my projects.


이찬희 (MarkiiimarK)
Never Stop Learning.