Skip to content

Commit 316c842

Browse files
committed
What's new docs for 10.0.0-preview.7
1 parent 11449dc commit 316c842

File tree

2 files changed

+81
-13
lines changed

2 files changed

+81
-13
lines changed

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

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,66 @@ In EF 10 we improved this experience - EF will now materialize a default value f
115115

116116
## LINQ and SQL translation
117117

118-
<a name="support-left-join"></a>
118+
<a name="parameterized-collection-translation"></a>
119+
120+
### Improved translation for parameterized collection
121+
122+
A notoriously difficult problem with relational databases is queries that involve *parameterized collections*:
123+
124+
```c#
125+
int[] ids = [1, 2, 3];
126+
var blogs = await context.Blogs.Where(b => ids.Contains(b.Id)).ToListAsync();
127+
```
128+
129+
In the above query, `ids` is a parameterized collection: the same query can be executed many times, with `ids` containing different values each time.
130+
131+
Since relational databases don't typically support sending a collection directly as a parameter, EF version up to 8.0 simply inlined the collection contents into the SQL as constants:
132+
133+
```sql
134+
SELECT [b].[Id], [b].[Name]
135+
FROM [Blogs] AS [b]
136+
WHERE [b].[Id] IN (1, 2, 3)
137+
```
138+
139+
While this works, it has the unfortunate consequence of generating different SQLs for different collections, causing database plan cache misses and bloat, and creating various performance problems (see [#13617](https://github.com/dotnet/efcore/issues/13617), which was the most highly-voted issue in the repo at the time). As a result, EF 8.0 leveraged the introduction of extensive JSON support and changed the translation of parameterized collections to use JSON arrays ([release notes](xref:core/what-is-new/ef-core-8.0/whatsnew#queries-with-primitive-collections
140+
)):
141+
142+
```sql
143+
@__ids_0='[1,2,3]'
144+
145+
SELECT [b].[Id], [b].[Name]
146+
FROM [Blogs] AS [b]
147+
WHERE [b].[Id] IN (
148+
SELECT [i].[value]
149+
FROM OPENJSON(@__ids_0) WITH ([value] int '$') AS [i]
150+
)
151+
```
152+
153+
Here, the collection is encoded as a string containing a JSON array, sent as a single parameter and then unpacked using the SQL Server [`OPENJSON`](/sql/t-sql/functions/openjson-transact-sql) function (other databases use similar mechanisms). Since the collection is now parameterized, the SQL stays the same and a single query plan no matter what values the collection contains. Unfortunately, while elegant, this translation also deprives the database query planner of important information on the cardinality (or length) of the collection, and can cause a plan to be chosen that works well for a small - or large - number of elements. As a result, EF Core 9.0 introduced the ability to control which translation strategy to use ([release notes](xref:core/what-is-new/ef-core-9.0/whatsnew#parameterized-primitive-collections)).
154+
155+
EF 10.0 introduces a new default translation mode for parameterized collections, where each value in the collection is traslated into its own scalar parameter:
156+
157+
```sql
158+
SELECT [b].[Id], [b].[Name]
159+
FROM [Blogs] AS [b]
160+
WHERE [b].[Id] IN (@ids1, @ids2, @ids3)
161+
```
162+
163+
This allows the collection values to change without resulting in different SQLs - solving the plan cache problem - but at the same time provides the query planner with information on the collection cardinality. Since different cardinalities still cause different SQLs to be generated, the final version of EF 10 will include a "bucketization" feature, where e.g. 10 parameters are sent even when the user only specifies 8, to reduce the SQL variations and optimize the query cache.
164+
165+
Unfortunately, parameterized collections are a case where EF simply cannot always make the right choice: selecting between multiple parameters (the new default), a single JSON array parameter or multiple inlined constants can require knowledge about the data in your database, and different choices may work better for different queries. As a result, EF exposes full control to the user to control the translation strategy, both at the global configuration level:
166+
167+
```c#
168+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
169+
=> optionsBuilder
170+
.UseSqlServer("<CONNECTION STRING>", o => o.UseParameterizedCollectionMode(ParameterTranslationMode.Constant));
171+
```
172+
173+
... and at the per-query level:
174+
175+
```c#
176+
var blogs = await context.Blogs.Where(b => EF.Constant(ids).Contains(b.Id)).ToListAsync();
177+
```
119178

120179
### Support for the .NET 10 `LeftJoin` and `RightJoin` operators
121180

@@ -140,24 +199,33 @@ var query = context.Students
140199
> [!NOTE]
141200
> EF 10 also supports the analogous `RightJoin` operator, which keeps all the data from the second collection and only the matching data from the first collection. EF 10 translates this to `RIGHT JOIN` operation in the database.
142201
202+
Unfortunately, C# query syntax (`from x select x.Id`) doesn't yet support expressing left/right join operations in this way.
203+
143204
See [#12793](https://github.com/dotnet/efcore/issues/12793) and [#35367](https://github.com/dotnet/efcore/issues/35367) for more details.
144205

145206
<a name="other-query-improvements"></a>
146207

147208
### Other query improvements
148209

210+
#### New translations
211+
149212
- Translate [DateOnly.ToDateTime()](/dotnet/api/system.dateonly.todatetime) ([#35194](https://github.com/dotnet/efcore/pull/35194), contributed by [@mseada94](https://github.com/mseada94)).
150213
- Translate [DateOnly.DayNumber](/dotnet/api/system.dateonly.daynumber) and `DayNumber` subtraction for SQL Server and SQLite ([#36183](https://github.com/dotnet/efcore/issues/36183)).
151-
- Optimize multiple consecutive `LIMIT`s ([#35384](https://github.com/dotnet/efcore/pull/35384), contributed by [@ranma42](https://github.com/ranma42)).
152-
- Optimize use of `Count` operation on `ICollection<T>` ([#35381](https://github.com/dotnet/efcore/pull/35381), contributed by [@ChrisJollyAU](https://github.com/ChrisJollyAU)).
153-
- Optimize `MIN`/`MAX` over `DISTINCT` ([#34699](https://github.com/dotnet/efcore/pull/34699), contributed by [@ranma42](https://github.com/ranma42)).
154214
- Translate date/time functions using `DatePart.Microsecond` and `DatePart.Nanosecond` arguments ([#34861](https://github.com/dotnet/efcore/pull/34861)).
155-
- Simplify parameter names (e.g. from `@__city_0` to `@city`) ([#35200](https://github.com/dotnet/efcore/pull/35200)).
156215
- Translate `COALESCE` as `ISNULL` on SQL Server, for most cases ([#34171](https://github.com/dotnet/efcore/pull/34171), contributed by [@ranma42](https://github.com/ranma42)).
157216
- Support some string functions taking `char` as arguments ([#34999](https://github.com/dotnet/efcore/pull/34999), contributed by [@ChrisJollyAU](https://github.com/ChrisJollyAU)).
158217
- Support `MAX`/`MIN`/`ORDER BY` using `decimal` on SQLite ([#35606](https://github.com/dotnet/efcore/pull/35606), contributed by [@ranma42](https://github.com/ranma42)).
159218
- Support projecting different navigations (but same type) via conditional operator ([#34589](https://github.com/dotnet/efcore/issues/34589), contributed by [@ranma42](https://github.com/ranma42)).
160219

220+
#### Bug fixes and optimizations
221+
222+
- Fix Microsoft.Data.Sqlite behavior around `DateTime`, `DateTimeOffset` and UTC, [see breaking change notes](xref:core/what-is-new/ef-core-9.0/whatsnew/ef-core-10.0/breaking-changes#DateTimeOffset-read) ([#36195](https://github.com/dotnet/efcore/issues/36195)).
223+
- Fix translation of `DefaultIfEmpty` in various scenarios ([#19095](https://github.com/dotnet/efcore/issues/19095), [#33343](https://github.com/dotnet/efcore/issues/33343), [#36208](https://github.com/dotnet/efcore/issues/36208)).
224+
- Optimize multiple consecutive `LIMIT`s ([#35384](https://github.com/dotnet/efcore/pull/35384), contributed by [@ranma42](https://github.com/ranma42)).
225+
- Optimize use of `Count` operation on `ICollection<T>` ([#35381](https://github.com/dotnet/efcore/pull/35381), contributed by [@ChrisJollyAU](https://github.com/ChrisJollyAU)).
226+
- Optimize `MIN`/`MAX` over `DISTINCT` ([#34699](https://github.com/dotnet/efcore/pull/34699), contributed by [@ranma42](https://github.com/ranma42)).
227+
- Simplify parameter names (e.g. from `@__city_0` to `@city`) ([#35200](https://github.com/dotnet/efcore/pull/35200)).
228+
161229
## ExecuteUpdateAsync now accepts a regular, non-expression lambda
162230

163231
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:

entity-framework/toc.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,38 +75,38 @@
7575
href: core/what-is-new/ef-core-9.0/breaking-changes.md
7676
- name: EF Core 8.0
7777
items:
78-
- name: High-level plan
79-
href: core/what-is-new/ef-core-8.0/plan.md
8078
- name: "What's new?"
8179
href: core/what-is-new/ef-core-8.0/whatsnew.md
8280
- name: Breaking changes
8381
href: core/what-is-new/ef-core-8.0/breaking-changes.md
82+
- name: High-level plan
83+
href: core/what-is-new/ef-core-8.0/plan.md
8484
- name: Out of support
8585
items:
8686
- name: EF Core 7.0
8787
items:
88-
- name: High-level plan
89-
href: core/what-is-new/ef-core-7.0/plan.md
9088
- name: "What's new?"
9189
href: core/what-is-new/ef-core-7.0/whatsnew.md
9290
- name: Breaking changes
9391
href: core/what-is-new/ef-core-7.0/breaking-changes.md
92+
- name: High-level plan
93+
href: core/what-is-new/ef-core-7.0/plan.md
9494
- name: EF Core 6.0
9595
items:
96-
- name: High-level plan
97-
href: core/what-is-new/ef-core-6.0/plan.md
9896
- name: "What's new?"
9997
href: core/what-is-new/ef-core-6.0/whatsnew.md
10098
- name: Breaking changes
10199
href: core/what-is-new/ef-core-6.0/breaking-changes.md
100+
- name: High-level plan
101+
href: core/what-is-new/ef-core-6.0/plan.md
102102
- name: EF Core 5.0
103103
items:
104-
- name: High-level plan
105-
href: core/what-is-new/ef-core-5.0/plan.md
106104
- name: "What's new?"
107105
href: core/what-is-new/ef-core-5.0/whatsnew.md
108106
- name: Breaking changes
109107
href: core/what-is-new/ef-core-5.0/breaking-changes.md
108+
- name: High-level plan
109+
href: core/what-is-new/ef-core-5.0/plan.md
110110
- name: EF Core 3.1
111111
items:
112112
- name: New features

0 commit comments

Comments
 (0)