From 59cea3b432c9d368baea63991c50bff702688d0f Mon Sep 17 00:00:00 2001 From: AndriySvyryd Date: Tue, 8 Sep 2020 19:00:51 -0700 Subject: [PATCH] Add some breaking changes Fixes #2526 Fixes #2585 Fixes #2225 Fixes #2546 --- .vscode/settings.json | 4 + .../ef-core-5.0/breaking-changes.md | 139 +++++++++++++++++- 2 files changed, 139 insertions(+), 4 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a9f7d36f85..659084c6a4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,5 +8,9 @@ "VB.NET", "XAML", "XML" + ], + "cSpell.words": [ + "mitigations", + "navigations" ] } diff --git a/entity-framework/core/what-is-new/ef-core-5.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-5.0/breaking-changes.md index cf60809c23..1fdda8a1f9 100644 --- a/entity-framework/core/what-is-new/ef-core-5.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-5.0/breaking-changes.md @@ -2,7 +2,7 @@ title: Breaking changes in EF Core 5.0 - EF Core description: Complete list of breaking changes introduced in Entity Framework Core 5.0 author: bricelam -ms.date: 06/05/2020 +ms.date: 09/08/2020 uid: core/what-is-new/ef-core-5.0/breaking-changes --- @@ -12,10 +12,15 @@ The following API and behavior changes have the potential to break existing appl ## Summary -| **Breaking change** | **Impact** | -|:----------------------------------------------------------------------------------------------------------------------------------|------------| -| [Removed HasGeometricDimension method from SQLite NTS extension](#removed-hasgeometricdimension-method-from-sqlite-nts-extension) | Low | +| **Breaking change** | **Impact** | +|:--------------------------------------------------------------------------------------------------------------------------------------|------------| +| [Removed HasGeometricDimension method from SQLite NTS extension](#geometric-sqlite) | Low | +| [Required on the navigation from principal to dependent has different semantics](#required-dependent) | Medium | +| [Value generators are called when the entity state is changed from Detached to Unchanged, Updated or Deleted](#non-added-generation") | Low | +| [IMigrationsModelDiffer now uses IRelationalModel](#relational-model) | Low | +| [Discriminators are read-only](#read-only-discriminators) | Low | + ### Removed HasGeometricDimension method from SQLite NTS extension [Tracking Issue #14257](https://github.com/aspnet/EntityFrameworkCore/issues/14257) @@ -47,3 +52,129 @@ modelBuilder.Entity( x.Property(e => e.Point).HasColumnType("POINTZ"); }); ``` + + +### Required on the navigation from principal to dependent has different semantics + +[Tracking Issue #17286](https://github.com/aspnet/EntityFrameworkCore/issues/17286) + +**Old behavior** + +Only the navigations to principal could be configured as required. Therefore using `RequiredAttribute` on the navigation to the dependent (the entity containing the foreign key) would instead create the foreign key on the defining entity type. + +**New behavior** + +With the added support for required dependents it is now possible to mark any reference navigation as required, meaning that in the case shown above the foreign key will be defined on the other side of the relationship and the properties won't be marked as required. + +Calling `IsRequired` before specifying the dependent end is now ambiguous: + +```cs +modelBuilder.Entity() + .HasOne(b => b.BlogImage) + .WithOne(i => i.Blog) + .IsRequired() + .HasForeignKey(b => b.BlogForeignKey); +``` + +**Why** + +The new behavior is necessary to enable support for required dependents ([see #12100](https://github.com/dotnet/efcore/issues/12100)). + +**Mitigations** + +Remove `RequiredAttribute` from the navigation to the dependent and place it instead on the navigation to the principal or configure the relationship in `OnModelCreating`: + +```cs +modelBuilder.Entity() + .HasOne(b => b.BlogImage) + .WithOne(i => i.Blog) + .HasForeignKey(b => b.BlogForeignKey) + .IsRequired(); +``` + + +### Value generators are called when the entity state is changed from Detached to Unchanged, Updated or Deleted + +[Tracking Issue #15289](https://github.com/aspnet/EntityFrameworkCore/issues/15289) + +**Old behavior** + +Value generators were only called when the entity state changed to Added. + +**New behavior** + +Value generators are now called when the entity state is changed from Detached to Unchanged, Updated or Deleted and the property contains the default values. + +**Why** + +This change was necessary to improve the experience with properties that are not persisted to the data store and have their value generated always on the client. + +**Mitigations** + +To prevent the value generator from being called assign a non-default value to the property before the state is changed. + + +### IMigrationsModelDiffer now uses IRelationalModel + +[Tracking Issue #20305](https://github.com/aspnet/EntityFrameworkCore/issues/20305) + +**Old behavior** + +`IMigrationsModelDiffer` API was defined using `IModel`. + +**New behavior** + +`IMigrationsModelDiffer` API now uses `IRelationalModel`. However the model snapshot still contains only `IModel` as this code is part of the application and Entity Framework can't change it without making a bigger breaking change. + +**Why** + +`IRelationalModel` is a newly added representation of the database schema. Using it to find differences is faster and more accurate. + +**Mitigations** + +Use the following code to compare the model from `snapshot` with the model from `context`: + +```cs +var dependencies = context.GetService(); +var relationalDependencies = context.GetService(); + +var typeMappingConvention = new TypeMappingConvention(dependencies); +typeMappingConvention.ProcessModelFinalizing(((IConventionModel)modelSnapshot.Model).Builder, null); + +var relationalModelConvention = new RelationalModelConvention(dependencies, relationalDependencies); +var sourceModel = relationalModelConvention.ProcessModelFinalized(snapshot.Model); + +var modelDiffer = context.GetService(); +var hasDifferences = modelDiffer.HasDifferences( + ((IMutableModel)sourceModel).FinalizeModel().GetRelationalModel(), + context.Model.GetRelationalModel()); +``` + +We are planning to improve this experience in 6.0 ([see #22031](https://github.com/dotnet/efcore/issues/22031)) + + +### Discriminators are read-only + +[Tracking Issue #21154](https://github.com/aspnet/EntityFrameworkCore/issues/21154) + +**Old behavior** + +It was possible to change the discriminator value before calling `SaveChanges` + +**New behavior** + +An exception will be throws in the above case. + +**Why** + +EF doesn't expect the entity type to change while it is still being tracked, so changing the discriminator value leaves the context in an inconsistent state which might result in unexpected behavior. + +**Mitigations** + +If changing the discriminator value is necessary and the context will be disposed immediately after calling `SaveChanges` the discriminator can be made mutable: + +```cs +modelBuilder.Entity() + .Property("Discriminator") + .Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Save); +```