Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some breaking changes #2621

Merged
merged 1 commit into from
Sep 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,9 @@
"VB.NET",
"XAML",
"XML"
],
"cSpell.words": [
"mitigations",
"navigations"
AndriySvyryd marked this conversation as resolved.
Show resolved Hide resolved
]
}
139 changes: 135 additions & 4 deletions entity-framework/core/what-is-new/ef-core-5.0/breaking-changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
---

Expand All @@ -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** |
|:--------------------------------------------------------------------------------------------------------------------------------------|------------|
| [Required on the navigation from principal to dependent has different semantics](#required-dependent) | Medium |
AndriySvyryd marked this conversation as resolved.
Show resolved Hide resolved
| [Removed HasGeometricDimension method from SQLite NTS extension](#geometric-sqlite) | Low |
| [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 |

<a name="geometric-sqlite"></a>
### Removed HasGeometricDimension method from SQLite NTS extension

[Tracking Issue #14257](https://github.com/aspnet/EntityFrameworkCore/issues/14257)
Expand Down Expand Up @@ -47,3 +52,129 @@ modelBuilder.Entity<GeoEntity>(
x.Property(e => e.Point).HasColumnType("POINTZ");
});
```

<a name="required-dependent"></a>
### 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<Blog>()
.HasOne(b => b.BlogImage)
.WithOne(i => i.Blog)
.IsRequired()
.HasForeignKey<BlogImage>(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<Blog>()
.HasOne(b => b.BlogImage)
.WithOne(i => i.Blog)
.HasForeignKey<BlogImage>(b => b.BlogForeignKey)
.IsRequired();
```

<a name="non-added-generation"></a>
### 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.

<a name="relational-model"></a>
### 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still have an issue to update the snapshot, right? I'd really like to do that if we can...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean dotnet/efcore#18557? It would still be opt-in, so we'll have to support old snapshots for a while.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kind of... We could switch to new snapshots only having a RelationalModel but the default implementation could get it from any existing IModel. That command would just help "normalize" old migrations and snapshots.


**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<ProviderConventionSetBuilderDependencies>();
var relationalDependencies = context.GetService<RelationalConventionSetBuilderDependencies>();

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<IMigrationsModelDiffer>();
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))

<a name="read-only-discriminators"></a>
### 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<BaseEntity>()
.Property<string>("Discriminator")
.Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Save);
```