-
Notifications
You must be signed in to change notification settings - Fork 2k
Updates to breaking changes #4673
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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)); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ajcvickers we still only show the convention below for adding triggers to all tables (rather than using the new UseSqlOutputClause() mechanism) - I'm wondering whether we're missing functionality or something for doing UseSqlOutputClause() from a convention (or should we just doc it?) |
||
| } | ||
| ``` | ||
|
|
||
| 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: | ||
|
|
||
|
|
@@ -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) | ||
|
|
@@ -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 | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 | ||
|
|
||
|
|
@@ -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 | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The main breaking change here is that EF 8.0 will generate a migration changing the discriminator column from
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's not really the break we're trying to document. The migration is an appropriate way to manage the change. However, this is not the case when Migrations is not able to automatically make the change, such as when the column is part of an index, since the index would need to dropped and re-created, and EF doesn't do that, so it fails.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see, ok. It still may be worth explaining that an unexpected migration is created (and why) as background etc. But no big deal either way.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I added another sentence to that effect. |
||
|
|
||
| [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); | ||
| }); | ||
| } | ||
| ``` | ||
Uh oh!
There was an error while loading. Please reload this page.