diff --git a/entity-framework/core/performance/advanced-performance-topics.md b/entity-framework/core/performance/advanced-performance-topics.md index bcd662ae1f..c39b4bfe67 100644 --- a/entity-framework/core/performance/advanced-performance-topics.md +++ b/entity-framework/core/performance/advanced-performance-topics.md @@ -295,6 +295,7 @@ Compiled models have some limitations: * [Global query filters are not supported](https://github.com/dotnet/efcore/issues/24897). * [Lazy loading and change-tracking proxies are not supported](https://github.com/dotnet/efcore/issues/24902). +* Value converters that reference private methods are not supported. Make referenced methods public or internal instead. * [The model must be manually synchronized by regenerating it any time the model definition or configuration change](https://github.com/dotnet/efcore/issues/24894). * Custom IModelCacheKeyFactory implementations are not supported. However, you can compile multiple models and load the appropriate one as needed. diff --git a/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md index 070c493be1..5f3f2292d6 100644 --- a/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md @@ -24,6 +24,9 @@ This page documents API and behavior changes that have the potential to break ex |:--------------------------------------------------------------------------------------------------------------- | -----------| | [SQL Server json data type used by default on Azure SQL and compatibility level 170](#sqlserver-json-data-type) | Low | | [ExecuteUpdateAsync now accepts a regular, non-expression lambda](#ExecuteUpdateAsync-lambda) | Low | +| [Complex type column names are now uniquified](#complex-type-column-uniquification) | Low | +| [Nested complex type properties use full path in column names](#nested-complex-type-column-names) | Low | +| [IDiscriminatorPropertySetConvention signature changed](#discriminator-convention-signature) | Low | ## Low-impact changes @@ -178,6 +181,93 @@ await context.Blogs.ExecuteUpdateAsync(s => }); ``` + + +### Complex type column names are now uniquified + +[Tracking Issue #4970](https://github.com/dotnet/EntityFramework.Docs/issues/4970) + +#### Old behavior + +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. + +#### New behavior + +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. + +#### Why + +This prevents data corruption that could occur when multiple properties are unintentionally mapped to the same column. + +#### Mitigations + +If you need multiple properties to share the same column, configure them explicitly: + +```c# +modelBuilder.Entity(b => +{ + b.ComplexProperty(c => c.ShippingAddress, p => p.Property(a => a.Street).HasColumnName("Street")); + b.ComplexProperty(c => c.BillingAddress, p => p.Property(a => a.Street).HasColumnName("Street")); +}); +``` + + + +### Nested complex type properties use full path in column names + +#### Old behavior + +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`. + +#### New behavior + +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`. + +#### Why + +This provides better column name uniqueness and makes it clearer which property maps to which column. + +#### Mitigations + +If you need to maintain the old column names, configure them explicitly: + +```c# +modelBuilder.Entity() + .ComplexProperty(e => e.Complex) + .ComplexProperty(o => o.NestedComplex) + .Property(c => c.Property) + .HasColumnName("NestedComplex_Property"); +``` + + + +### IDiscriminatorPropertySetConvention signature changed + +#### Old behavior + +Previously, `IDiscriminatorPropertySetConvention.ProcessDiscriminatorPropertySet` took `IConventionEntityTypeBuilder` as a parameter. + +#### New behavior + +Starting with EF Core 10.0, the method signature changed to take `IConventionTypeBaseBuilder` instead of `IConventionEntityTypeBuilder`. + +#### Why + +This change allows the convention to work with both entity types and complex types. + +#### Mitigations + +Update your custom convention implementations to use the new signature: + +```c# +public virtual void ProcessDiscriminatorPropertySet( + IConventionTypeBaseBuilder typeBaseBuilder, // Changed from IConventionEntityTypeBuilder + string name, + Type type, + MemberInfo memberInfo, + IConventionContext context) +``` + ## Microsoft.Data.Sqlite breaking changes diff --git a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md index 44f38c5155..459cea6c47 100644 --- a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md @@ -29,6 +29,7 @@ EF Core 9 targets .NET 8. This means that existing applications that target .NET | [Exception is thrown when applying migrations in an explicit transaction](#migrations-transaction) | High | | [`Microsoft.EntityFrameworkCore.Design` not found when using EF tools](#tools-design) | Medium | | [`EF.Functions.Unhex()` now returns `byte[]?`](#unhex) | Low | +| [Compiled models now reference value converter methods directly](#compiled-model-private-methods) | Low | | [SqlFunctionExpression's nullability arguments' arity validated](#sqlfunctionexpression-nullability) | Low | | [`ToString()` method now returns empty string for `null` instances](#nullable-tostring) | Low | | [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) Otherwise, add runtime checks for null on the return value of Unhex(). + + +### Compiled models now reference value converter methods directly + +[Tracking Issue #35033](https://github.com/dotnet/efcore/issues/35033) + +#### Old behavior + +Previously, when using value converters with compiled models (using `dotnet ef dbcontext optimize`), EF would reference the converter type and everything worked correctly. + +```c# +public sealed class BooleanToCharConverter() : ValueConverter(v => ConvertToChar(v), v => ConvertToBoolean(v)) +{ + public static readonly BooleanToCharConverter Default = new(); + + private static char ConvertToChar(bool value) // Private method + => value ? 'Y' : 'N'; + + private static bool ConvertToBoolean(char value) // Private method + => value == 'Y'; +} +``` + +#### New behavior + +Starting with EF Core 9.0, EF generates code that directly references the conversion methods themselves. If these methods are private, compilation will fail. + +#### Why + +This change was necessary to support NativeAOT. + +#### Mitigations + +Make the methods referenced by value converters public or internal instead of private. + ### SqlFunctionExpression's nullability arguments' arity validated