Skip to content

Commit 0ae6eac

Browse files
Document breaking changes for complex types in EF Core 10.0 (#5113)
Column name uniquification Nested complex type column naming IDiscriminatorPropertySetConvention signature change Value converters with private methods in compiled models Fixes #4970 Fixes #4947 Fixes dotnet/efcore#35033 Co-authored-by: AndriySvyryd <[email protected]>
1 parent c2db051 commit 0ae6eac

File tree

3 files changed

+127
-0
lines changed

3 files changed

+127
-0
lines changed

entity-framework/core/performance/advanced-performance-topics.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ Compiled models have some limitations:
295295

296296
* [Global query filters are not supported](https://github.com/dotnet/efcore/issues/24897).
297297
* [Lazy loading and change-tracking proxies are not supported](https://github.com/dotnet/efcore/issues/24902).
298+
* Value converters that reference private methods are not supported. Make referenced methods public or internal instead.
298299
* [The model must be manually synchronized by regenerating it any time the model definition or configuration change](https://github.com/dotnet/efcore/issues/24894).
299300
* Custom IModelCacheKeyFactory implementations are not supported. However, you can compile multiple models and load the appropriate one as needed.
300301

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

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ This page documents API and behavior changes that have the potential to break ex
2424
|:--------------------------------------------------------------------------------------------------------------- | -----------|
2525
| [SQL Server json data type used by default on Azure SQL and compatibility level 170](#sqlserver-json-data-type) | Low |
2626
| [ExecuteUpdateAsync now accepts a regular, non-expression lambda](#ExecuteUpdateAsync-lambda) | Low |
27+
| [Complex type column names are now uniquified](#complex-type-column-uniquification) | Low |
28+
| [Nested complex type properties use full path in column names](#nested-complex-type-column-names) | Low |
29+
| [IDiscriminatorPropertySetConvention signature changed](#discriminator-convention-signature) | Low |
2730

2831
## Low-impact changes
2932

@@ -178,6 +181,93 @@ await context.Blogs.ExecuteUpdateAsync(s =>
178181
});
179182
```
180183

184+
<a name="complex-type-column-uniquification"></a>
185+
186+
### Complex type column names are now uniquified
187+
188+
[Tracking Issue #4970](https://github.com/dotnet/EntityFramework.Docs/issues/4970)
189+
190+
#### Old behavior
191+
192+
Previously, when mapping complex types to table columns, if multiple properties in different complex types had the same column name, they would silently share the same column.
193+
194+
#### New behavior
195+
196+
Starting with EF Core 10.0, complex type column names are uniquified by appending a number at the end if another column with the same name exists on the table.
197+
198+
#### Why
199+
200+
This prevents data corruption that could occur when multiple properties are unintentionally mapped to the same column.
201+
202+
#### Mitigations
203+
204+
If you need multiple properties to share the same column, configure them explicitly:
205+
206+
```c#
207+
modelBuilder.Entity<Customer>(b =>
208+
{
209+
b.ComplexProperty(c => c.ShippingAddress, p => p.Property(a => a.Street).HasColumnName("Street"));
210+
b.ComplexProperty(c => c.BillingAddress, p => p.Property(a => a.Street).HasColumnName("Street"));
211+
});
212+
```
213+
214+
<a name="nested-complex-type-column-names"></a>
215+
216+
### Nested complex type properties use full path in column names
217+
218+
#### Old behavior
219+
220+
Previously, properties on nested complex types were mapped to columns using just the declaring type name. For example, `EntityType.Complex.NestedComplex.Property` was mapped to column `NestedComplex_Property`.
221+
222+
#### New behavior
223+
224+
Starting with EF Core 10.0, properties on nested complex types use the full path to the property as part of the column name. For example, `EntityType.Complex.NestedComplex.Property` is now mapped to column `Complex_NestedComplex_Property`.
225+
226+
#### Why
227+
228+
This provides better column name uniqueness and makes it clearer which property maps to which column.
229+
230+
#### Mitigations
231+
232+
If you need to maintain the old column names, configure them explicitly:
233+
234+
```c#
235+
modelBuilder.Entity<EntityType>()
236+
.ComplexProperty(e => e.Complex)
237+
.ComplexProperty(o => o.NestedComplex)
238+
.Property(c => c.Property)
239+
.HasColumnName("NestedComplex_Property");
240+
```
241+
242+
<a name="discriminator-convention-signature"></a>
243+
244+
### IDiscriminatorPropertySetConvention signature changed
245+
246+
#### Old behavior
247+
248+
Previously, `IDiscriminatorPropertySetConvention.ProcessDiscriminatorPropertySet` took `IConventionEntityTypeBuilder` as a parameter.
249+
250+
#### New behavior
251+
252+
Starting with EF Core 10.0, the method signature changed to take `IConventionTypeBaseBuilder` instead of `IConventionEntityTypeBuilder`.
253+
254+
#### Why
255+
256+
This change allows the convention to work with both entity types and complex types.
257+
258+
#### Mitigations
259+
260+
Update your custom convention implementations to use the new signature:
261+
262+
```c#
263+
public virtual void ProcessDiscriminatorPropertySet(
264+
IConventionTypeBaseBuilder typeBaseBuilder, // Changed from IConventionEntityTypeBuilder
265+
string name,
266+
Type type,
267+
MemberInfo memberInfo,
268+
IConventionContext<IConventionProperty> context)
269+
```
270+
181271
<a name="MDS-breaking-changes"></a>
182272

183273
## Microsoft.Data.Sqlite breaking changes

entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ EF Core 9 targets .NET 8. This means that existing applications that target .NET
2929
| [Exception is thrown when applying migrations in an explicit transaction](#migrations-transaction) | High |
3030
| [`Microsoft.EntityFrameworkCore.Design` not found when using EF tools](#tools-design) | Medium |
3131
| [`EF.Functions.Unhex()` now returns `byte[]?`](#unhex) | Low |
32+
| [Compiled models now reference value converter methods directly](#compiled-model-private-methods) | Low |
3233
| [SqlFunctionExpression's nullability arguments' arity validated](#sqlfunctionexpression-nullability) | Low |
3334
| [`ToString()` method now returns empty string for `null` instances](#nullable-tostring) | Low |
3435
| [Shared framework dependencies were updated to 9.0.x](#shared-framework-dependencies) | Low |
@@ -228,6 +229,41 @@ var binaryData = await context.Blogs.Select(b => EF.Functions.Unhex(b.HexString)
228229

229230
Otherwise, add runtime checks for null on the return value of Unhex().
230231

232+
<a name="compiled-model-private-methods"></a>
233+
234+
### Compiled models now reference value converter methods directly
235+
236+
[Tracking Issue #35033](https://github.com/dotnet/efcore/issues/35033)
237+
238+
#### Old behavior
239+
240+
Previously, when using value converters with compiled models (using `dotnet ef dbcontext optimize`), EF would reference the converter type and everything worked correctly.
241+
242+
```c#
243+
public sealed class BooleanToCharConverter() : ValueConverter<bool, char>(v => ConvertToChar(v), v => ConvertToBoolean(v))
244+
{
245+
public static readonly BooleanToCharConverter Default = new();
246+
247+
private static char ConvertToChar(bool value) // Private method
248+
=> value ? 'Y' : 'N';
249+
250+
private static bool ConvertToBoolean(char value) // Private method
251+
=> value == 'Y';
252+
}
253+
```
254+
255+
#### New behavior
256+
257+
Starting with EF Core 9.0, EF generates code that directly references the conversion methods themselves. If these methods are private, compilation will fail.
258+
259+
#### Why
260+
261+
This change was necessary to support NativeAOT.
262+
263+
#### Mitigations
264+
265+
Make the methods referenced by value converters public or internal instead of private.
266+
231267
<a name="sqlfunctionexpression-nullability"></a>
232268

233269
### SqlFunctionExpression's nullability arguments' arity validated

0 commit comments

Comments
 (0)