Skip to content

Commit 8923440

Browse files
committed
Document ExecuteUpdate support for complex JSON (#5094)
See dotnet/efcore#28766
1 parent d2839f4 commit 8923440

File tree

1 file changed

+66
-18
lines changed
  • entity-framework/core/what-is-new/ef-core-10.0

1 file changed

+66
-18
lines changed

entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md

Lines changed: 66 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -224,24 +224,6 @@ In previous versions of EF Core, evolving the model when using Azure Cosmos DB w
224224

225225
In EF 10 we improved this experience - EF will now materialize a default value for a required property, if no data is present for it in the document, rather than throw.
226226

227-
<a name="named-query-filters"></a>
228-
229-
## Named query filters
230-
231-
EF's [global query filters](xref:core/querying/filters) feature has long enabled users to configuring filters to entity types which apply to all queries by default. This has simplified implementing common patterns and scenarios such as soft deletion, multitenancy and others. However, up to now EF has only supported a single query filter per entity type, making it difficult to have multiple filters and selectively disabling only some of them in specific queries.
232-
233-
EF 10 introduces *named query filters*, which allow attaching names to query filter and managing each one separately:
234-
235-
[!code-csharp[Main](../../../../samples/core/Querying/QueryFilters/NamedFilters.cs#FilterConfiguration)]
236-
237-
This notably allows disabling only certain filters in a specific LINQ query:
238-
239-
[!code-csharp[Main](../../../../samples/core/Querying/QueryFilters/NamedFilters.cs#DisableSoftDeletionFilter)]
240-
241-
For more information on named query filters, [see the documentation](xref:core/querying/filters).
242-
243-
This feature was contributed by [@bittola](https://github.com/bittola).
244-
245227
<a name="linq-and-sql-translation"></a>
246228

247229
## LINQ and SQL translation
@@ -414,6 +396,72 @@ ORDER BY [b0].[Name], [b0].[Id]
414396
- Optimize `MIN`/`MAX` over `DISTINCT` ([#34699](https://github.com/dotnet/efcore/pull/34699), contributed by [@ranma42](https://github.com/ranma42)).
415397
- Simplify parameter names (e.g. from `@__city_0` to `@city`) ([#35200](https://github.com/dotnet/efcore/pull/35200)).
416398

399+
<a name="execute-update-json"></a>
400+
401+
## ExecuteUpdate support for relational JSON columns
402+
403+
> [!NOTE]
404+
> ExecuteUpdate support for JSON requires mapping your types as complex types, and does not work when you types are mapped as owned entities.
405+
406+
Although EF has support JSON columns for some time and allows updating them via `SaveChanges`, `ExecuteUpdate` lacked support for them. EF10 now allows referencing JSON columns and properties within them in `ExecuteUpdate`, allowing efficient bulk updating of document-modeled data within relational databases.
407+
408+
For example, given the following model, mapping the `BlogDetails` type to a complex JSON column in the database:
409+
410+
```c#
411+
public class Blog
412+
{
413+
public int Id { get; set; }
414+
415+
public BlogDetails Details { get; set; }
416+
}
417+
418+
public class BlogDetails
419+
{
420+
public string Title { get; set; }
421+
public int Views { get; set; }
422+
}
423+
424+
protected override void OnModelCreating(ModelBuilder modelBuilder)
425+
{
426+
modelBuilder.Entity<Blog>().ComplexProperty(b => b.Details, bd => bd.ToJson());
427+
}
428+
```
429+
430+
You can now use `ExecuteUpdate` as usual, referencing properties within `BlogDetails`:
431+
432+
```c#
433+
await context.Blogs.ExecuteUpdateAsync(s =>
434+
s.SetProperty(b => b.Details.Views, b => b.Details.Views + 1));
435+
```
436+
437+
This generates the following for SQL Server 2025, using the efficient, new `modify` function to increment the JSON property `Views` by one:
438+
439+
```sql
440+
UPDATE [b]
441+
SET [Details].modify('$.Views', JSON_VALUE([b].[Details], '$.Views' RETURNING int) + 1)
442+
FROM [Blogs] AS [b]
443+
```
444+
445+
Older versions of SQL Server are also supported, where the JSON data is stored in an `nvarchar(max)` column rather than the new JSON data type support. For support with other databases, consult the documentation for your EF provider.
446+
447+
<a name="named-query-filters"></a>
448+
449+
## Named query filters
450+
451+
EF's [global query filters](xref:core/querying/filters) feature has long enabled users to configuring filters to entity types which apply to all queries by default. This has simplified implementing common patterns and scenarios such as soft deletion, multitenancy and others. However, up to now EF has only supported a single query filter per entity type, making it difficult to have multiple filters and selectively disabling only some of them in specific queries.
452+
453+
EF 10 introduces *named query filters*, which allow attaching names to query filter and managing each one separately:
454+
455+
[!code-csharp[Main](../../../../samples/core/Querying/QueryFilters/NamedFilters.cs#FilterConfiguration)]
456+
457+
This notably allows disabling only certain filters in a specific LINQ query:
458+
459+
[!code-csharp[Main](../../../../samples/core/Querying/QueryFilters/NamedFilters.cs#DisableSoftDeletionFilter)]
460+
461+
For more information on named query filters, [see the documentation](xref:core/querying/filters).
462+
463+
This feature was contributed by [@bittola](https://github.com/bittola).
464+
417465
## ExecuteUpdateAsync now accepts a regular, non-expression lambda
418466

419467
The <xref:Microsoft.EntityFrameworkCore.RelationalQueryableExtensions.ExecuteUpdateAsync*> can be used to express arbitrary update operations in the database. In previous versions, the changes to be performed on the database rows were provided via an expression tree parameter; this made it quite difficult to build those changes dynamically. For example, let's assume we want to update a Blog's Views, but conditionally also its Name. Since the setters argument was an expression tree, code such as the following needed to be written:

0 commit comments

Comments
 (0)