Skip to content

Commit

Permalink
Updates to breaking changes (#4673)
Browse files Browse the repository at this point in the history
* Updates to breaking changes

Fixes #4608
Part of #4538
Fixes #4315
Fixes #4257
Fixes #4655
Fixes #4654

* Update entity-framework/core/what-is-new/ef-core-6.0/breaking-changes.md

Co-authored-by: Shay Rojansky <roji@roji.org>

* Updates

---------

Co-authored-by: Shay Rojansky <roji@roji.org>
  • Loading branch information
ajcvickers and roji committed Mar 10, 2024
1 parent 66cbb8f commit c19932c
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 5 deletions.
30 changes: 30 additions & 0 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 @@ -44,6 +44,7 @@ EF Core 6.0 targets .NET 6. Applications targeting older .NET, .NET Core, and .N
| [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 |
| [`NavigationBaseIncludeIgnored` is now an error by default](#ignored-navigation) | Low |

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

Expand Down Expand Up @@ -944,3 +945,32 @@ public object Create(DbContext context, bool designTime)
? (context.GetType(), dynamicContext.UseIntProperty, designTime)
: (object)context.GetType();
```

The navigation '{navigation}' was ignored from 'Include' in the query since the fix-up will automatically populate it. If any further navigations are specified in 'Include' afterwards then they will be ignored. Walking back in the include tree is not allowed.

<a name="ignored-navigation"></a>

### `NavigationBaseIncludeIgnored` is now an error by default

[Tracking Issue #4315](https://github.com/dotnet/EntityFramework.Docs/issues/4315)
#### Old behavior

The event `CoreEventId.NavigationBaseIncludeIgnored` was logged as a warning by default.

#### New behavior

The event `CoreEventId.NavigationBaseIncludeIgnored` was logged as an error by default and causes an exception to be thrown.

#### Why

These query patterns are not allowed, so EF Core now throws to indicate that the queries should be updated.

#### Mitigations

The old behavior can be restored by configuring the event as a warning. For example:

```csharp
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.ConfigureWarnings(b => b.Warn(CoreEventId.NavigationBaseIncludeIgnored));
```
30 changes: 25 additions & 5 deletions entity-framework/core/what-is-new/ef-core-7.0/breaking-changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,21 @@ The performance improvements linked to the new method are significant enough tha

#### Mitigations

You can let EF Core know that the target table has a trigger; doing so will revert to the previous, less efficient technique. This can be done by configuring the corresponding entity type as follows:
Starting with EF Core 8.0, the use or not of the "OUTPUT" clause can be configured explicitly. For example:

```csharp
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.ToTable(tb => tb.UseSqlOutputClause(false));
}
```

In EF7 or later, If the target table has a trigger, then you can let EF Core know this, and EF will revert to the previous, less efficient technique. This can be done by configuring the corresponding entity type as follows:

[!code-csharp[Main](../../../../samples/core/SqlServer/Misc/TriggersContext.cs?name=TriggerConfiguration&highlight=4)]

Note that doing this doesn't actually make EF Core create or manage the trigger in any way - it currently only informs EF Core that triggers are present on the table. As a result, any trigger name can be used, and this can also be used if an unsupported computed column is in use (regardless of triggers).
Note that doing this doesn't actually make EF Core create or manage the trigger in any way - it currently only informs EF Core that triggers are present on the table. As a result, any trigger name can be used. Specifying a trigger can be used to revert the old behavior _even if there isn't actually a trigger in the table_.

If most or all of your tables have triggers, you can opt out of using the newer, efficient technique for all your model's tables by using the following model building convention:

Expand Down Expand Up @@ -167,7 +177,17 @@ The simplifications and performance improvements linked to the new method are si

#### Mitigations

In EF Core 8.0, a mechanism will be introduced that will allow specifying whether to use the new mechanism on a table-by-table basis. With EF Core 7.0, it's possible to revert to the old mechanism for the entire application by inserting the following code in your context configuration:
In EF Core 8.0, the `UseSqlReturningClause` method has been introduced to explicitly revert back to the older, less efficient SQL. For example:

```csharp
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.ToTable(tb => tb.UseSqlReturningClause(false));
}
```

If you are still using EF Core 7.0, then it's possible to revert to the old mechanism for the entire application by inserting the following code in your context configuration:

```c#
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
Expand Down Expand Up @@ -493,11 +513,11 @@ Query or attach entities before marking entities as `Deleted`, or manually set n

#### Old behavior

In EF Core 6.0, using the Azure Cosmos DB <xref:Microsoft.EntityFrameworkCore.CosmosQueryableExtensions.FromSqlRaw%2A> extension method when using a relational provider, or the relational <xref:Microsoft.EntityFrameworkCore.RelationalQueryableExtensions.FromSqlRaw%2A> extension method when using the Azure Cosmos DB provider could silently fail.
In EF Core 6.0, using the Azure Cosmos DB <xref:Microsoft.EntityFrameworkCore.CosmosQueryableExtensions.FromSqlRaw%2A> extension method when using a relational provider, or the relational <xref:Microsoft.EntityFrameworkCore.RelationalQueryableExtensions.FromSqlRaw%2A> extension method when using the Azure Cosmos DB provider could silently fail. Likewise, using relational methods on the in-memory provider is a silent no-op.

#### New behavior

Starting with EF Core 7.0, using the wrong extension method will throw an exception.
Starting with EF Core 7.0, using an extension method designed for one provider on a different provider will throw an exception.

#### Why

Expand Down
96 changes: 96 additions & 0 deletions entity-framework/core/what-is-new/ef-core-8.0/breaking-changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ EF Core 8 targets .NET 8. Applications targeting older .NET, .NET Core, and .NET
| [ExcludeFromMigrations no longer excludes other tables in a TPC hierarchy](#exclude-from-migrations) | Low |
| [Non-shadow integer keys are persisted to Cosmos documents](#persist-to-cosmos) | Low |
| [Relational model is generated in the compiled model](#compiled-relational-model) | Low |
| [Scaffolding may generate different navigation names](#navigation-names) | Low |
| [Discriminators now have a max length](#discriminators) | Low |
| [SQL Server key values are compared case-insensitively](#casekeys) | Low |

## High-impact changes

Expand Down Expand Up @@ -437,3 +440,96 @@ This was done to further improve startup time.
#### Mitigations

Edit the generated `*ModelBuilder.cs` file and remove the line `AddRuntimeAnnotation("Relational:RelationalModel", CreateRelationalModel());` as well as the method `CreateRelationalModel()`.

<a name="navigation-names"></a>

### Scaffolding may generate different navigation names

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

Previously when scaffolding a `DbContext` and entity types from an existing database, the navigation names for relationships were sometimes derived from a common prefix of multiple foreign key column names.

#### New behavior

Starting with EF Core 8.0, common prefixes of column names from a composite foreign key are no longer used to generate navigation names.

#### Why

This is an obscure naming rule which sometimes generates very poor names like, `S`, `Student_`, or even just `_`. Without this rule, strange names are no longer generated, and the naming conventions for navigations are also made simpler, thereby making it easier to understand and predict which names will be generated.

#### Mitigations

The [EF Core Power Tools](https://github.com/ErikEJ/EFCorePowerTools/issues/2143) have an option to keep generating navigations in the old way. Alternatively, the code generated can be fully customized using [T4 templates](xref:core/managing-schemas/scaffolding/templates). This can be used to example the foreign key properties of scaffolding relationships and use whatever rule is appropriate for your code to generate the navigation names you need.
<a name="discriminators"></a>

### Discriminators now have a max length

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

Previously, discriminator columns created for [TPH inheritance mapping](xref:core/modeling/inheritance) were configured as `nvarchar(max)` on SQL Server/Azure SQL, or the equivalent unbounded string type on other databases.

#### New behavior

Starting with EF Core 8.0, discriminator columns are created with a max length that covers all the known discriminator values. EF will generate a migration to make this change. However, if the discriminator column is constrained in some way--for example, as part of an index--then the `AlterColumn` created by Migrations may fail.

#### Why

`nvarchar(max)` columns are inefficient and unnecessary when the lengths of all possible values are known.

#### Mitigations

The column size can be made explicitly unbounded:

```csharp
modelBuilder.Entity<Foo>()
.Property<string>("Discriminator")
.HasMaxLength(-1);
```

<a name="casekeys"></a>

### SQL Server key values are compared case-insensitively

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

Previously, when tracking entities with string keys with the SQL Server/Azure SQL database providers, the key values were compared using the default .NET case-sensitive ordinal comparer.

#### New behavior

Starting with EF Core 8.0, SQL Server/Azure SQL string key values are compared using the default .NET case-insensitive ordinal comparer.

#### Why

By default, SQL Server uses case-insensitive comparisons when comparing foreign key values for matches to principal key values. This means when EF uses case-sensitive comparisons it may not connect a foreign key to a principal key when it should.

#### Mitigations

Case-sensitive comparisons can be used by setting a custom `ValueComparer`. For example:

```csharp
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var comparer = new ValueComparer<string>(
(l, r) => string.Equals(l, r, StringComparison.Ordinal),
v => v.GetHashCode(),
v => v);

modelBuilder.Entity<Blog>()
.Property(e => e.Id)
.Metadata.SetValueComparer(comparer);

modelBuilder.Entity<Post>(
b =>
{
b.Property(e => e.Id).Metadata.SetValueComparer(comparer);
b.Property(e => e.BlogId).Metadata.SetValueComparer(comparer);
});
}
```

0 comments on commit c19932c

Please sign in to comment.