Skip to content

Commit

Permalink
EF Core 5.0/6.0 breaking change updates
Browse files Browse the repository at this point in the history
Fixes #3915
Fixes #4024
Fixes #3851
Fixes #3663

Supersedes #4016
  • Loading branch information
ajcvickers committed Sep 21, 2022
1 parent 3479399 commit b956a30
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 34 deletions.
12 changes: 10 additions & 2 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: 10/08/2021
ms.date: 09/21/2022
uid: core/what-is-new/ef-core-5.0/breaking-changes
---

Expand Down Expand Up @@ -81,7 +81,15 @@ We marked this method as obsolete to guide users to a more accurate overload - <

#### Mitigations

Use the following code to get the column name for a specific table:
If the entity type is only ever mapped to a single table, and never to views, functions, or multiple tables, the <xref:Microsoft.EntityFrameworkCore.RelationalPropertyExtensions.GetColumnBaseName> can be used in EF Core 5.0 and 6.0 to obtain the table name. For example:

```csharp
var columnName = property.GetColumnBaseName();
```

In EF Core 7.0, this can again be replaced with the new `GetColumnName`, which behaves as the original did for simple, single table only mappings.

If the entity type may be mapped to views, functions, or multiple tables, then a <xref:Microsoft.EntityFrameworkCore.Metadata.StoreObjectIdentifier> must be obtained to identity the table, view, or function. This can be then be used to get the column name for that store object. For example:

```csharp
var columnName = property.GetColumnName(StoreObjectIdentifier.Table("Users", null)));
Expand Down
131 changes: 100 additions & 31 deletions entity-framework/core/what-is-new/ef-core-6.0/breaking-changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,49 @@
title: Breaking changes in EF Core 6.0 - EF Core
description: Complete list of breaking changes introduced in Entity Framework Core 6.0
author: ajcvickers
ms.date: 01/10/2022
ms.date: 09/21/2022
uid: core/what-is-new/ef-core-6.0/breaking-changes
---

# Breaking changes in EF Core 6.0

The following API and behavior changes have the potential to break existing applications updating to EF Core 6.0.0.
The following API and behavior changes have the potential to break existing applications updating to EF Core 6.0.


## Target Framework

EF Core 6.0 targets .NET 6. Applications targeting older .NET, .NET Core, and .NET Framework versions will need to target .NET 6 to use EF Core 6.0.

## Summary

| **Breaking change** | **Impact** |
|:--------------------------------------------------------------------------------------------------------------------------------------|------------|
| [Nested optional dependents sharing a table and with no required properties cannot be saved](#nested-optionals) | High |
| [Changing the owner of an owned entity now throws an exception](#owned-reparenting) | Medium |
| [Cosmos: Related entity types are discovered as owned](#cosmos-owned) | Medium |
| [SQLite: Connections are pooled](#connection-pool) | Medium |
| [Many-to-many relationships without mapped join entities are now scaffolded](#many-to-many) | Medium |
| [Cleaned up mapping between DeleteBehavior and ON DELETE values](#on-delete) | Low |
| [In-memory database validates required properties do not contain nulls](#in-memory-required) | Low |
| [Removed last ORDER BY when joining for collections](#last-order-by) | Low |
| [DbSet no longer implements IAsyncEnumerable](#dbset-iasyncenumerable) | Low |
| [TVF return entity type is also mapped to a table by default](#tvf-table) | Low |
| [Check constraint name uniqueness is now validated](#unique-check-constraints) | Low |
| [Added IReadOnly Metadata interfaces and removed extension methods](#ireadonly-metadata) | Low |
| [IExecutionStrategy is now a singleton service](#iexecutionstrategy) | Low |
| [SQL Server: More errors are considered transient](#transient-errors) | Low |
| [Cosmos: More characters are escaped in 'id' values](#cosmos-id) | Low |
| [Some Singleton services are now Scoped](#query-services) | Low* |
| [New caching API for extensions that add or replace services](#extensions-caching) | Low* |
| [New snapshot and design-time model initialization procedure](#snapshot-initialization) | Low |
| [`OwnedNavigationBuilder.HasIndex` returns a different type now](#owned-index) | Low |
| [`DbFunctionBuilder.HasSchema(null)` overrides `[DbFunction(Schema = "schema")]`](#function-schema) | Low |
| [Pre-initialized navigations are overridden by values from database queries](#overwrite-navigations) | Low |
| [Unknown enum string values in the database are not converted to the enum default when queried](#unknown-emums) | Low |
| [DbFunctionBuilder.HasTranslation now provides the function arguments as IReadOnlyList rather than IReadOnlyCollection](#func-args) | Low |
| [Default table mapping is not removed when the entity is mapped to a table-valued function](#tvf-default-mapping) | Low |
| [dotnet-ef targets .NET 6](#dotnet-ef) | Low |
| **Breaking change** | **Impact** |
|:------------------------------------------------------------------------------------------------------------------------------------|------------|
| [Nested optional dependents sharing a table and with no required properties cannot be saved](#nested-optionals) | High |
| [Changing the owner of an owned entity now throws an exception](#owned-reparenting) | Medium |
| [Cosmos: Related entity types are discovered as owned](#cosmos-owned) | Medium |
| [SQLite: Connections are pooled](#connection-pool) | Medium |
| [Many-to-many relationships without mapped join entities are now scaffolded](#many-to-many) | Medium |
| [Cleaned up mapping between DeleteBehavior and ON DELETE values](#on-delete) | Low |
| [In-memory database validates required properties do not contain nulls](#in-memory-required) | Low |
| [Removed last ORDER BY when joining for collections](#last-order-by) | Low |
| [DbSet no longer implements IAsyncEnumerable](#dbset-iasyncenumerable) | Low |
| [TVF return entity type is also mapped to a table by default](#tvf-table) | Low |
| [Check constraint name uniqueness is now validated](#unique-check-constraints) | Low |
| [Added IReadOnly Metadata interfaces and removed extension methods](#ireadonly-metadata) | Low |
| [IExecutionStrategy is now a singleton service](#iexecutionstrategy) | Low |
| [SQL Server: More errors are considered transient](#transient-errors) | Low |
| [Cosmos: More characters are escaped in 'id' values](#cosmos-id) | Low |
| [Some Singleton services are now Scoped](#query-services) | Low* |
| [New caching API for extensions that add or replace services](#extensions-caching) | Low* |
| [New snapshot and design-time model initialization procedure](#snapshot-initialization) | Low |
| [`OwnedNavigationBuilder.HasIndex` returns a different type now](#owned-index) | Low |
| [`DbFunctionBuilder.HasSchema(null)` overrides `[DbFunction(Schema = "schema")]`](#function-schema) | Low |
| [Pre-initialized navigations are overridden by values from database queries](#overwrite-navigations) | Low |
| [Unknown enum string values in the database are not converted to the enum default when queried](#unknown-emums) | Low |
| [DbFunctionBuilder.HasTranslation now provides the function arguments as IReadOnlyList rather than IReadOnlyCollection](#func-args) | Low |
| [Default table mapping is not removed when the entity is mapped to a table-valued function](#tvf-default-mapping) | Low |
| [dotnet-ef targets .NET 6](#dotnet-ef) | Low |
| [`IModelCacheKeyFactory` implementations may need to be updated to handle design-time caching](#model-cache-key) | Low |

\* These changes are of particular interest to authors of database providers and extensions.

Expand Down Expand Up @@ -98,9 +104,41 @@ Using models with nested optional dependents sharing a table and with no require

Avoid using optional dependents sharing a table and with no required properties. There are three easy ways to do this:

1. Make the dependents required. This means that the dependent entity will always have a value after it is queried, even if all its properties are null.
1. Make the dependents required. This means that the dependent entity will always have a value after it is queried, even if all its properties are null. For example:

```csharp
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }

[Required]
public Address Address { get; set; }
}
```

Or:

```csharp
modelBuilder.Entity<Customer>(
b =>
{
b.OwnsOne(e => e.Address);
b.Navigation(e => e.Address).IsRequired();
});
```

2. Make sure that the dependent contains at least one required property.
3. Map optional dependents to their own table, instead of sharing a table with the principal.
3. Map optional dependents to their own table, instead of sharing a table with the principal. For example:

```csharp
modelBuilder.Entity<Customer>(
b =>
{
b.ToTable("Customers");
b.OwnsOne(e => e.Address, b => b.ToTable("CustomerAddresses"));
});
```

The problems with optional dependents and examples of these mitigations are included in the documentation for [What's new in EF Core 6.0](xref:core/what-is-new/ef-core-6.0/whatsnew#changes-to-owned-optional-dependent-handling).

Expand Down Expand Up @@ -876,3 +914,34 @@ To run dotnet-ef without installing the .NET 6 runtime, you can install an older
```dotnetcli
dotnet tool install dotnet-ef --version 3.1.*
```

<a name="model-cache-key"></a>

### `IModelCacheKeyFactory` implementations may need to be updated to handle design-time caching

[Tracking Issue #25154](https://github.com/dotnet/efcore/issues/25154)
#### Old behavior

`IModelCacheKeyFactory` did not have an option to cache the design-time model separately from the runtime model.

#### New behavior

`IModelCacheKeyFactory` has a new overload that allows the design-time model to be cached separately from the runtime model. Not implementing this method may result in an exception similar to:

> System.InvalidOperationException: 'The requested configuration is not stored in the read-optimized model, please use 'DbContext.GetService&lt;IDesignTimeModel&gt;().Model'.'

#### Why

Implementation of compiled models required separation of the design-time (used when building the model) and runtime (used when executing queries, etc.) models. If the runtime code needs access to design-time information, then the design-time model must be cached.

#### Mitigations

Implement the new overload. For example:

```csharp
public object Create(DbContext context, bool designTime)
=> context is DynamicContext dynamicContext
? (context.GetType(), dynamicContext.UseIntProperty, designTime)
: (object)context.GetType();
```
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ uid: core/what-is-new/ef-core-7.0/breaking-changes

# Breaking changes in EF Core 7.0 (EF7)

API and behavior changes have the potential to break existing applications updating to EF Core 7.0 (EF7) are be documented here.
The following API and behavior changes have the potential to break existing applications updating to EF Core 7.0.

## Target Framework

Expand Down

0 comments on commit b956a30

Please sign in to comment.