@@ -12,11 +12,17 @@ This page documents API and behavior changes that have the potential to break ex
12
12
13
13
## Summary
14
14
15
- | ** Breaking change** | ** Impact** |
16
- | :---------------------------------------------------------------------------------------------------------| ------------|
17
- | [ ` Contains ` in LINQ queries may stop working on older SQL Server versions | High |
18
- | [ SQL Server ` date ` and ` time ` now scaffold to .NET ` DateOnly ` and ` TimeOnly ` ] ( #sqlserver-date-time-only ) | Medium |
19
- | [ SQLite ` Math ` methods now translate to SQL] ( #sqlite-math ) | Low |
15
+ | ** Breaking change** | ** Impact** |
16
+ | :--------------------------------------------------------------------------------------------------------------| ------------|
17
+ | [ ` Contains ` in LINQ queries may stop working on older SQL Server versions] ( #sqlserver-contains-compatibility ) | High |
18
+ | [ Enums in JSON are stored as ints instead of strings by default] ( #enums-as-ints ) | High |
19
+ | [ SQL Server ` date ` and ` time ` now scaffold to .NET ` DateOnly ` and ` TimeOnly ` ] ( #sqlserver-date-time-only ) | Medium |
20
+ | [ Boolean columns with a database generated value are no longer scaffolded as nullable] ( #scaffold-bools ) | Medium |
21
+ | [ SQLite ` Math ` methods now translate to SQL] ( #sqlite-math ) | Low |
22
+ | [ ITypeBase replaces IEntityType in some APIs] ( #type-base ) | Low |
23
+ | [ ValueGenerator expressions must use public APIs] ( #value-converters ) | Low |
24
+ | [ ExcludeFromMigrations no longer excludes other tables in a TPC hierarchy] ( #exclude-from-migrations ) | Low |
25
+ | [ Non-shadow integer keys are persisted to Cosmos documents] ( #persist-to-cosmos ) | Low |
20
26
21
27
## High-impact changes
22
28
@@ -78,6 +84,32 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
78
84
.UseSqlServer (@" <CONNECTION STRING>" , o => o .UseCompatibilityLevel (120 ));
79
85
```
80
86
87
+ <a name =" enums-as-ints " ></a >
88
+
89
+ ### Enums in JSON are stored as ints instead of strings by default
90
+
91
+ [ Tracking Issue #13617 ] ( https://github.com/dotnet/efcore/issues/31100 )
92
+
93
+ #### Old behavior
94
+
95
+ In EF7, [ enums mapped to JSON] ( xref:core/what-is-new/ef-core-7.0/whatsnew#json-columns ) are, by default, stored as string values in the JSON document.
96
+
97
+ #### New behavior
98
+
99
+ Starting with EF Core 8.0, EF now, by default, maps enums to integer values in the JSON document.
100
+
101
+ #### Why
102
+
103
+ EF has always, by default, mapped enums to a numeric column in relational databases. Since EF supports queries where values from JSON interact with values from columns and parameters, it is important that the values in JSON match the values in the non-JSON column.
104
+
105
+ #### Mitigations
106
+
107
+ To continue using strings, configure the enum property with a conversion. For example:
108
+
109
+ ``` csharp
110
+ modelBuilder .Entity <User >().Property (e => e .Status ).HasConversion <string >();
111
+ ```
112
+
81
113
## Medium-impact changes
82
114
83
115
<a name =" sqlserver-date-time-only " ></a >
@@ -123,6 +155,42 @@ It is recommended to react to this change by modifying your code to use the newl
123
155
< #
124
156
```
125
157
158
+ < a name = " scaffold-bools" >< / a >
159
+
160
+ ### Boolean columns with a database generated value are no longer scaffolded as nullable
161
+
162
+ [Tracking Issue #15070 ](https :// github.com/dotnet/efcore/issues/15070)
163
+
164
+ #### Old behavior
165
+
166
+ Previously , non - nullable `bool ` columns with a database default constraint were scaffolded as nullable `bool ? ` properties .
167
+
168
+ #### New behavior
169
+
170
+ Starting with EF Core 8 . 0 , non - nullable `bool ` columns are always scaffolded as non - nullable properties .
171
+
172
+ #### Why
173
+
174
+ A `bool ` property will not have its value sent to the database if that value is `false `, which is the CLR default . If the database has a default value of `true ` for the column , then even though the value of the property is `false `, the value in the database ends up as `true `. However , in EF8 , the sentinel used to determine if a property has a value or not can be changed . This is done automatically for `bool ` properties with a database generated value of `true `, which means that it is no longer necessary to scaffold the properties as nullable .
175
+
176
+ #### Mitigations
177
+
178
+ This change only affects users which regularly re -scaffold their database into an EF code model (" database-first" flow ).
179
+
180
+ It is recommended to react to this change by modifying your code to use the non -nullable bool property . However , if that isn 't possible, you can edit the scaffolding templates to revert to the previous mapping. To do this, set up the templates as described on [this page](xref:core/managing-schemas/scaffolding/templates). Then, edit the `EntityType.t4` file, find where the entity properties get generated (search for `property.ClrType`), and change the code to the following:
181
+
182
+ ```c #
183
+ #>
184
+ var propertyClrType = property .ClrType != typeof (bool )
185
+ || (property .GetDefaultValueSql () == null && property .GetDefaultValue () != null )
186
+ ? property .ClrType
187
+ : typeof (bool ?);
188
+ #>
189
+ public < #= code .Reference (propertyClrType ) #>< #= needsNullable ? " ?" : " " #> < #= property .Name #> { get ; set ; }< #= needsInitializer ? " = null!;" : " " #>
190
+ < #
191
+ < #
192
+ ```
193
+
126
194
## Low-impact changes
127
195
128
196
< a name = " sqlite-math" >< / a >
@@ -196,3 +264,128 @@ var query = dbContext.Cylinders
196
264
Volume = Math .PI * Math .Pow (c .Radius , 2 ) * c .Height
197
265
});
198
266
```
267
+
268
+ < a name = " type-base" >< / a >
269
+
270
+ ### ITypeBase replaces IEntityType in some APIs
271
+
272
+ [Tracking Issue #13947 ](https :// github.com/dotnet/efcore/issues/13947)
273
+
274
+ #### Old behavior
275
+
276
+ Previously , all mapped structural types were entity types .
277
+
278
+ #### New behavior
279
+
280
+ With the introduction of complex types in EF8 , some APIs that were previously use an `IEntityType ` now use `ITypeBase ` so that the APIs can be used with either entity or complex types . This includes :
281
+
282
+ - `IProperty .DeclaringEntityType ` is now obsolete and `IProperty .DeclaringType ` should be used instead .
283
+ - `IEntityTypeIgnoredConvention ` is now obsolete and `ITypeIgnoredConvention ` should be used instead .
284
+
285
+ #### Why
286
+
287
+ With the introduction of complex types in EF8 , these APIs can be used with either `IEntityType ` or `IComplexType `.
288
+
289
+ #### Mitigations
290
+
291
+ The old APIs are obsoleted , but will not be removed until EF10 . Code should be updated to use the new APIs ASAP .
292
+
293
+ < a name = " value-converters" >< / a >
294
+
295
+ ### ValueConverter and ValueComparer expressions must use public APIs for the compiled model
296
+
297
+ [Tracking Issue #24896 ](https :// github.com/dotnet/efcore/issues/24896)
298
+
299
+ #### Old behavior
300
+
301
+ Previously , `ValueConverter ` and `ValueComparer ` definitions where not included in the compiled model , and so could contain arbitrary code .
302
+
303
+ #### New behavior
304
+
305
+ EF now extracts the expressions from the `ValueConverter ` and `ValueComparer ` objects and includes these C # in the compiled model . This means that these expressions must only use public API .
306
+
307
+ #### Why
308
+
309
+ The EF team is gradually moving more constructs into the compiled model to support using EF Core with AOT in the future .
310
+
311
+ #### Mitigations
312
+
313
+ Make the APIs used by the comparer public . For example , consider this simple converter :
314
+
315
+ ```csharp
316
+ public class MyValueConverter : ValueConverter < string , byte []>
317
+ {
318
+ public MyValueConverter ()
319
+ : base (v => ConvertToBytes (v ), v => ConvertToString (v ))
320
+ {
321
+ }
322
+
323
+ private static string ConvertToString (byte [] bytes )
324
+ => " " ; // ... TODO: Conversion code
325
+
326
+ private static byte [] ConvertToBytes (string chars )
327
+ => Array .Empty <byte >(); // ... TODO: Conversion code
328
+ }
329
+ ```
330
+
331
+ To use this converter in a compiled model with EF8 , the `ConvertToString ` and `ConvertToBytes ` methods must be made public . For example :
332
+
333
+ ```csharp
334
+ public class MyValueConverter : ValueConverter < string , byte []>
335
+ {
336
+ public MyValueConverter ()
337
+ : base (v => ConvertToBytes (v ), v => ConvertToString (v ))
338
+ {
339
+ }
340
+
341
+ public static string ConvertToString (byte [] bytes )
342
+ => " " ; // ... TODO: Conversion code
343
+
344
+ public static byte [] ConvertToBytes (string chars )
345
+ => Array .Empty <byte >(); // ... TODO: Conversion code
346
+ }
347
+ ```
348
+
349
+ < a name = " exclude-from-migrations" >< / a >
350
+
351
+ ### ExcludeFromMigrations no longer excludes other tables in a TPC hierarchy
352
+
353
+ [Tracking Issue #30079 ](https :// github.com/dotnet/efcore/issues/30079)
354
+
355
+ #### Old behavior
356
+
357
+ Previously , using `ExcludeFromMigrations ` on a table in a TPC hierarchy would also exclude other tables in the hierarchy .
358
+
359
+ #### New behavior
360
+
361
+ Starting with EF Core 8 . 0 , `ExcludeFromMigrations ` does not impact other tables .
362
+
363
+ #### Why
364
+
365
+ The old behavior was a bug and prevented migrations from being used to manage hierarchies across projects .
366
+
367
+ #### Mitigations
368
+
369
+ Use `ExcludeFromMigrations ` explicitly on any other table that should be excluded .< a name = " exclude-from-migrations" >< / a >
370
+
371
+ < a name = " persist-to-cosmos" >< / a >
372
+
373
+ ### Non-shadow integer keys are persisted to Cosmos documents
374
+
375
+ [Tracking Issue #31664 ](https :// github.com/dotnet/efcore/issues/31664)
376
+
377
+ #### Old behavior
378
+
379
+ Previously , non - shadow integer properties that match the criteria to be a synthesized key property would not be persisted into the JSON document , but were instead re - synthesized on the way out .
380
+
381
+ #### New behavior
382
+
383
+ Starting with EF Core 8 . 0 , these properties are now persisted .
384
+
385
+ #### Why
386
+
387
+ The old behavior was a bug and prevented properties that match the synthesized key criteria from being persisted to Cosmos .
388
+
389
+ #### Mitigations
390
+
391
+ [Exclude the property from the model ](xref :core / modeling / entity - properties #included - and - excluded - properties ) if its value should not be persisted .
0 commit comments