Skip to main content

Updating Data

There are multiple ways to update data in EF Core. The simplest way may be to query the data to update first and then to update it in a second operation:

var author = _context.Authors.FirstOrDefault(a => a.FirstName == "Julie" && a.LastName == "Lerman");

if(author != null)
{
author.FirstName = "Julia";
_context.SaveChanges();
}

Efficient updating using ExecuteUpdate

ExecuteUpdate provides a similar way to express a SQL UPDATE statement:

context.Blogs
.Where(b => b.Rating < 3)
.ExecuteUpdate(setters => setters.SetProperty(b => b.IsVisible, false));

We first use LINQ to determine which Blogs should be affected, then need to express the change to be applied to the matching Blogs. This is done by calling SetProperty within the ExecuteUpdate call, and providing it with two arguments: the property to be changed (IsVisible), and the new value it should have (false). This causes the following SQL to be executed:

UPDATE [b]
SET [b].[IsVisible] = CAST(0 AS bit)
FROM [Blogs] AS [b]
WHERE [b].[Rating] < 3

Updating multiple properties

ExecuteUpdate allows updating multiple properties in a single invocation. For example, to both set IsVisible to false and to set Rating to zero, simply chain additional SetProperty calls together:

context.Blogs
.Where(b => b.Rating < 3)
.ExecuteUpdate(setters => setters
.SetProperty(b => b.IsVisible, false)
.SetProperty(b => b.Rating, 0));

This executes the following SQL:

UPDATE [b]
SET [b].[Rating] = 0,
[b].[IsVisible] = CAST(0 AS bit)
FROM [Blogs] AS [b]
WHERE [b].[Rating] < 3

Referencing the existing property value

The above examples updated the property to a new constant value. ExecuteUpdate also allows referencing the existing property value when calculating the new value; for example, to increase the rating of all matching Blogs by one, use the following:

context.Blogs
.Where(b => b.Rating < 3)
.ExecuteUpdate(setters => setters.SetProperty(b => b.Rating, b => b.Rating + 1));

Note that the second argument to SetProperty is now a lambda function, and not a constant as before. Its b parameter represents the Blog being updated; within that lambda, b.Rating thus contains the rating before any change occurred. This executes the following SQL:

UPDATE [b]
SET [b].[Rating] = [b].[Rating] + 1
FROM [Blogs] AS [b]
WHERE [b].[Rating] < 3

ExecuteUpdate does not currently support referencing navigations within the SetProperty lambda. For example, let's say we want to update all the Blogs' ratings so that each Blog's new rating is the average of all its Posts' ratings. We may try to use ExecuteUpdate as follows:

context.Blogs.ExecuteUpdate(
setters => setters.SetProperty(b => b.Rating, b => b.Posts.Average(p => p.Rating)));

However, EF does allow performing this operation by first using Select to calculate the average rating and project it to an anonymous type, and then using ExecuteUpdate over that:

context.Blogs
.Select(b => new { Blog = b, NewRating = b.Posts.Average(p => p.Rating) })
.ExecuteUpdate(setters => setters.SetProperty(b => b.Blog.Rating, b => b.NewRating));