Skip to content

Commit e63dece

Browse files
maumarroji
andauthored
whats new in EF 10 (#4921)
* whats new in EF 10 * Document ExecuteUpdateAsync lambda change (#4930) dotnet/efcore#32018 --------- Co-authored-by: Shay Rojansky <[email protected]>
1 parent 3ded403 commit e63dece

File tree

2 files changed

+163
-0
lines changed

2 files changed

+163
-0
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
---
2+
title: Breaking changes in EF Core 10 (EF10) - EF Core
3+
description: List of breaking changes introduced in Entity Framework Core 10 (EF10)
4+
author: maumar
5+
ms.date: 01/05/2025
6+
uid: core/what-is-new/ef-core-10.0/breaking-changes
7+
---
8+
9+
# Breaking changes in EF Core 10 (EF10)
10+
11+
This page documents API and behavior changes that have the potential to break existing applications updating from EF Core 9 to EF Core 10. Make sure to review earlier breaking changes if updating from an earlier version of EF Core:
12+
13+
- [Breaking changes in EF Core 9](xref:core/what-is-new/ef-core-9.0/breaking-changes)
14+
- [Breaking changes in EF Core 8](xref:core/what-is-new/ef-core-8.0/breaking-changes)
15+
- [Breaking changes in EF Core 7](xref:core/what-is-new/ef-core-7.0/breaking-changes)
16+
- [Breaking changes in EF Core 6](xref:core/what-is-new/ef-core-6.0/breaking-changes)
17+
18+
## Summary
19+
20+
| **Breaking change** | **Impact** |
21+
|:----------------------------------------------------------------------------------------------------------|------------|
22+
| [ExecuteUpdateAsync now accepts a regular, non-expression lambda](#ExecuteUpdateAsync-lambda) | Low |
23+
24+
## Low-impact changes
25+
26+
<a name="ExecuteUpdateAsync-lambda"></a>
27+
28+
### ExecuteUpdateAsync now accepts a regular, non-expression lambda
29+
30+
[Tracking Issue #32018](https://github.com/dotnet/efcore/issues/32018)
31+
32+
#### Old behavior
33+
34+
Previously, <xref:Microsoft.EntityFrameworkCore.RelationalQueryableExtensions.ExecuteUpdate*> accepted an expression tree argument (`Expression<Func<...>>`) for the column setters.
35+
36+
#### New behavior
37+
38+
Starting with EF Core 10.0, <xref:Microsoft.EntityFrameworkCore.RelationalQueryableExtensions.ExecuteUpdate*> now accepts a non-expression argument (`Func<...>`) for the column setters. If you were building expression trees to dynamically create the column setters argument, your code will no longer compile - but can be replaced with a much simpler alternative (see below).
39+
40+
#### Why
41+
42+
The fact that the column setters parameter was an expression tree made it quite difficult to do dynamic construction of the column setters, where some setters are only present based on some condition (see Mitigations below for an example).
43+
44+
#### Mitigations
45+
46+
Code that was building expression trees to dynamically create the column setters argument will need to be rewritten - but the result will be much simpler. 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:
47+
48+
```c#
49+
// Base setters - update the Views only
50+
Expression<Func<SetPropertyCalls<Blog>, SetPropertyCalls<Blog>>> setters =
51+
s => s.SetProperty(b => b.Views, 8);
52+
53+
// Conditionally add SetProperty(b => b.Name, "foo") to setters, based on the value of nameChanged
54+
if (nameChanged)
55+
{
56+
var blogParameter = Expression.Parameter(typeof(Blog), "b");
57+
58+
setters = Expression.Lambda<Func<SetPropertyCalls<Blog>, SetPropertyCalls<Blog>>>(
59+
Expression.Call(
60+
instance: setters.Body,
61+
methodName: nameof(SetPropertyCalls<Blog>.SetProperty),
62+
typeArguments: [typeof(string)],
63+
arguments:
64+
[
65+
Expression.Lambda<Func<Blog, string>>(Expression.Property(blogParameter, nameof(Blog.Name)), blogParameter),
66+
Expression.Constant("foo")
67+
]),
68+
setters.Parameters);
69+
}
70+
71+
await context.Blogs.ExecuteUpdateAsync(setters);
72+
```
73+
74+
Manually creating expression trees is complicated and error-prone, and made this common scenario much more difficult than it should have been. Starting with EF 10, you can now write the following instead:
75+
76+
```c#
77+
await context.Blogs.ExecuteUpdateAsync(s =>
78+
{
79+
s.SetProperty(b => b.Views, 8);
80+
if (nameChanged)
81+
{
82+
s.SetProperty(b => b.Name, "foo");
83+
}
84+
});
85+
```
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
---
2+
title: What's New in EF Core 10
3+
description: Overview of new features in EF Core 10
4+
author: maumar
5+
ms.date: 01/05/2025
6+
uid: core/what-is-new/ef-core-10.0/whatsnew
7+
---
8+
9+
# What's New in EF Core 10
10+
11+
EF Core 10 (EF10) is the next release after EF Core 9 and is scheduled for release in November 2025.
12+
13+
EF10 is available as [daily builds](https://github.com/dotnet/efcore/blob/main/docs/DailyBuilds.md) which contain all the latest EF10 features and API tweaks. The samples here make use of these daily builds.
14+
15+
> [!TIP]
16+
> You can run and debug into the samples by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs). Each section below links to the source code specific to that section.
17+
18+
EF10 requires the .NET 10 SDK to build and requires the .NET 10 runtime to run. EF10 will not run on earlier .NET versions, and will not run on .NET Framework.
19+
20+
> [!TIP]
21+
> The _What's New_ docs are updated for each preview. All the samples are set up to use the [EF10 daily builds](https://github.com/dotnet/efcore/blob/main/docs/DailyBuilds.md), which usually have several additional weeks of completed work compared to the latest preview. We strongly encourage use of the daily builds when testing new features so that you're not doing your testing against stale bits.
22+
23+
<a name="linq-and-sql-translation"></a>
24+
25+
## LINQ and SQL translation
26+
27+
<a name="other-query-improvements"></a>
28+
29+
### Other query improvements
30+
31+
* Translation for DateOnly.ToDateTime(timeOnly) ([#35194](https://github.com/dotnet/efcore/pull/35194), contributed by [@mseada94](https://github.com/mseada94)).
32+
* Optimization for multiple consecutive `LIMIT`s ([#35384](https://github.com/dotnet/efcore/pull/35384)), contributed by [@ranma42](https://github.com/ranma42)).
33+
* Optimization for use of `Count` operation on `ICollection<T>` ([#35381](https://github.com/dotnet/efcore/pull/35381)), contributed by [@ChrisJollyAU](https://github.com/ChrisJollyAU)).
34+
35+
## ExecuteUpdateAsync now accepts a regular, non-expression lambda
36+
37+
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:
38+
39+
```c#
40+
// Base setters - update the Views only
41+
Expression<Func<SetPropertyCalls<Blog>, SetPropertyCalls<Blog>>> setters =
42+
s => s.SetProperty(b => b.Views, 8);
43+
44+
// Conditionally add SetProperty(b => b.Name, "foo") to setters, based on the value of nameChanged
45+
if (nameChanged)
46+
{
47+
var blogParameter = Expression.Parameter(typeof(Blog), "b");
48+
49+
setters = Expression.Lambda<Func<SetPropertyCalls<Blog>, SetPropertyCalls<Blog>>>(
50+
Expression.Call(
51+
instance: setters.Body,
52+
methodName: nameof(SetPropertyCalls<Blog>.SetProperty),
53+
typeArguments: [typeof(string)],
54+
arguments:
55+
[
56+
Expression.Lambda<Func<Blog, string>>(Expression.Property(blogParameter, nameof(Blog.Name)), blogParameter),
57+
Expression.Constant("foo")
58+
]),
59+
setters.Parameters);
60+
}
61+
62+
await context.Blogs.ExecuteUpdateAsync(setters);
63+
```
64+
65+
Manually creating expression trees is complicated and error-prone, and made this common scenario much more difficult than it should have been. Starting with EF 10, you can now write the following instead:
66+
67+
```c#
68+
await context.Blogs.ExecuteUpdateAsync(s =>
69+
{
70+
s.SetProperty(b => b.Views, 8);
71+
if (nameChanged)
72+
{
73+
s.SetProperty(b => b.Name, "foo");
74+
}
75+
});
76+
```
77+
78+
Thanks to [@aradalvand](https://github.com/aradalvand) for proposing and pushing for this change (in [#32018](https://github.com/dotnet/efcore/issues/32018)).

0 commit comments

Comments
 (0)