Breaking Changes in EF Core 5.0

Die folgenden API-Änderungen und Behavior Changes können dazu führen, dass vorhandene Anwendungen nach einem Upgrade auf EF Core 5.0.0 nicht mehr funktionieren.

Zusammenfassung

Wichtige Änderung Auswirkungen
EF Core 5.0 unterstützt .NET Framework nicht Medium
IProperty.GetColumnName() gilt ab sofort als veraltet Medium
Genauigkeit und Skalierung sind für Dezimale erforderlich Medium
Andere Semantik für die erforderliche oder Non-Nullable-Navigation vom Prinzipal zur abhängigen Entität Medium
Die definierende Abfrage wurde durch anbieterspezifische Methoden ersetzt Medium
Navigationen ohne Nullverweis werden von Abfragen nicht überschrieben Medium
ToView() wird von Migrationen anders verarbeitet Medium
ToTable(null) markiert den Entitätstyp als nicht einer Tabelle zugeordnet Medium
Die HasGeometricDimension-Methode wurde aus der SQLite NTS-Erweiterung entfernt Niedrig
Azure Cosmos DB: Der Partitionsschlüssel wird nun dem Primärschlüssel hinzugefügt Niedrig
Azure Cosmos DB: id Eigenschaft umbenannt in__id Niedrig
Azure Cosmos DB: byte[] wird nun als Base64-Zeichenfolge statt als Zahlenarray gespeichert Niedrig
Azure Cosmos DB: GetPropertyName und SetPropertyName wurden umbenannt Niedrig
Wert-Generatoren werden aufgerufen, wenn der Entitätszustand von „Getrennt“ in „Unverändert“, „Aktualisiert“ oder „Gelöscht“ geändert wird Niedrig
IMigrationsModelDiffer verwendet jetzt IRelationalModel Niedrig
Diskriminatoren sind schreibgeschützt Niedrig
Anbieterspezifische EF.Functions-Methoden werden für InMemory-Anbieter ausgelöst. Niedrig
IndexBuilder.HasName ist mittlerweile veraltet Niedrig
Ein Pluralizer ist jetzt für das Gerüst von Reverse-Engineering-Modellen enthalten Niedrig
INavigationBase ersetzt INavigation in einigen APIs zur Unterstützung überspringender Navigationen Niedrig
Einige Abfragen mit korrelierter Sammlung, die ebenfalls Distinct oder GroupBy verwenden, werden nicht mehr unterstützt Niedrig
Die Verwendung einer Sammlung abfragbarer Typen in der Projektion wird nicht unterstützt Niedrig

Änderungen mit mittlerer Auswirkung

EF Core 5.0 unterstützt .NET Framework nicht

Issue #15498

Altes Verhalten

EF Core 3.1 ist auf .NET Standard 2.0 ausgelegt, was von .NET Framework unterstützt wird.

Neues Verhalten

EF Core 5.0 ist auf .NET Standard 2.1 ausgelegt, was nicht von .NET Framework unterstützt wird. Das bedeutet, EF Core 5.0 kann nicht mit .NET Framework-Anwendungen verwendet werden.

Warum?

Hierbei handelt es sich um einen Teil der umfassenderen Bewegung von .NET-Teams, um eine Vereinheitlichung in einem einzelnen .NET-Zielframework zu erreichen. Weitere Informationen finden Sie unter The future of .NET Standard (Die Zukunft von .NET Standard).

Gegenmaßnahmen

.NET Framework-Anwendungen können weiterhin EF Core 3.1 verwenden. Dabei handelt es sich um ein LTS-Release (Long-Term Support, langfristige Unterstützung). Alternativ können Anwendungen zur Verwendung von .NET Core 3.1 oder .NET 5 aktualisiert werden, um die Unterstützung von .NET Standard 2.1 zu nutzen.

IProperty.GetColumnName() gilt ab sofort als veraltet

Nachverfolgung von Issue #2266

Altes Verhalten

GetColumnName() hat den Namen der Spalte zurückgegeben, der die Eigenschaft zugeordnet ist.

Neues Verhalten

GetColumnName() gibt weiterhin den Namen der Spalte zurück, der eine Eigenschaft zugeordnet ist. Dieses Verhalten ist nun jedoch mehrdeutig, da EF Core 5 die TPT-Methode (Tabelle pro Typ) und gleichzeitiges Zuordnen zu einer Ansicht oder einer Funktion unterstützt, wenn diese Zuordnungen verschiedene Spaltennamen für dieselbe Eigenschaft verwenden könnten.

Warum?

Diese Methode wurde als veraltet gekennzeichnet, um Benutzern nahezulegen, eine exaktere Überladung zu verwenden: GetColumnName(IProperty, StoreObjectIdentifier).

Gegenmaßnahmen

Wenn der Entitätstyp immer nur einer einzigen Tabelle zugeordnet ist und niemals Ansichten, Funktionen oder mehreren Tabellen, kann die GetColumnBaseName(IReadOnlyProperty) in EF Core 5.0 und 6.0 verwendet werden, um den Tabellennamen zu erhalten. Beispiel:

var columnName = property.GetColumnBaseName();

In EF Core 7.0 kann dies wieder durch die neue GetColumnName ersetzt werden, die sich wie das Original für einfache, nur eine Tabelle betreffende Zuordnungen verhält.

Wenn der Entitätstyp Ansichten, Funktionen oder mehreren Tabellen zugeordnet werden kann, muss ein StoreObjectIdentifier abgerufen werden, um die Tabelle, Ansicht oder Funktion zu identifizieren. Dies kann dann verwendet werden, um den Spaltennamen für dieses Speicherobjekt abzurufen. Beispiel:

var columnName = property.GetColumnName(StoreObjectIdentifier.Table("Users", null)));

Genauigkeit und Skalierung sind für Dezimale erforderlich

Nachverfolgung von Issue #19293

Altes Verhalten

EF Core hat die Genauigkeit und Skalierung von SqlParameter-Objekten normalerweise nicht festgelegt. Das bedeutet, dass die vollständige Genauigkeit und Skalierung an SQL Server übermittelt wurde, sodass SQL Server anhand der Genauigkeit und Skalierung der Datenbankspalte aufgerundet hat.

Neues Verhalten

Nun legt EF Core die Genauigkeit und Skalierung für Parameter mithilfe der Werte fest, die für Eigenschaften im EF Core-Modell konfiguriert wurden. Das bedeutet, dass die Rundung jetzt in SqlClient erfolgt. Demnach kann sich die Rundung ändern, wenn die Genauigkeit und Skalierung nicht mit der Genauigkeit und Skalierung der Datenbank übereinstimmen.

Warum?

Neuere SQL Server-Features, einschließlich Always Encrypted, erfordern, dass Parameterfacetten vollständig festgelegt werden. Darüber hinaus hat SqlClient eine Änderung an der Rundung vorgenommen, anstatt Dezimalwerte zu kürzen, was dem Verhalten von SQL Server entspricht. Dadurch konnte EF Core diese Facetten festlegen, ohne das Verhalten für ordnungsgemäß konfigurierte Dezimale zu ändern.

Gegenmaßnahmen

Ordnen Sie Ihre Dezimaleigenschaften mithilfe eines Typnamens zu, der die Genauigkeit und Skalierung enthält. Beispiel:

public class Blog
{
    public int Id { get; set; }

    [Column(TypeName = "decimal(16, 5)")]
    public decimal Score { get; set; }
}

Alternativ können Sie HasPrecision in den APIs für die Modellerstellung verwenden. Beispiel:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>().Property(e => e.Score).HasPrecision(16, 5);
    }

Andere Semantik für die erforderliche oder Non-Nullable-Navigation vom Prinzipal zur abhängigen Entität

Tracking Issue 17286

Altes Verhalten

Nur die Navigation zum Prinzipal konnte als erforderlich konfiguriert werden. Daher führte RequiredAttribute, wenn es für die Navigation zur abhängigen Entität (die den Fremdschlüssel enthält) verwendet oder als Non-Nullable gekennzeichnet wurde, stattdessen zur Erstellung des Fremdschlüssels für den definierenden Entitätstyp.

Neues Verhalten

Dank der hinzugefügten Unterstützung von erforderlichen abhängigen Entitäten ist es nun möglich, jede beliebige Verweisnavigation als erforderlich zu markieren. Dies bedeutet, dass im obigen Fall der Fremdschlüssel auf der anderen Seite der Beziehung definiert wird und die Eigenschaften nicht als erforderlich markiert werden.

Das Aufrufen von IsRequired vor der Angabe der abhängigen Entität ist nun mehrdeutig:

modelBuilder.Entity<Blog>()
    .HasOne(b => b.BlogImage)
    .WithOne(i => i.Blog)
    .IsRequired()
    .HasForeignKey<BlogImage>(b => b.BlogForeignKey);

Warum?

Das neue Verhalten ist erforderlich, um die Unterstützung von erforderlichen abhängigen Entitäten zu ermöglichen (siehe 12100).

Gegenmaßnahmen

Entfernen Sie RequiredAttribute aus der Navigation zur abhängigen Entität, und verwenden Sie „RequiredAttribute“ stattdessen in der Navigation zum Prinzipal, oder konfigurieren Sie die Beziehung in OnModelCreating:

modelBuilder.Entity<Blog>()
    .HasOne(b => b.BlogImage)
    .WithOne(i => i.Blog)
    .HasForeignKey<BlogImage>(b => b.BlogForeignKey)
    .IsRequired();

Die definierende Abfrage wurde durch anbieterspezifische Methoden ersetzt

Issue 18903

Altes Verhalten

Entitätstypen wurden zum Definieren von Abfragen auf der Kernebene zugeordnet. Jedes Mal, wenn der Entitätstyp im Abfragestamm des Entitätstyps verwendet wurde, wurde er bei allen Anbietern durch die definierende Abfrage ersetzt.

Neues Verhalten

APIs für definierende Abfragen sind veraltet. Es wurden neue anbieterspezifische APIs eingeführt.

Warum?

Während definierende Abfragen als Ersatzabfragen implementiert wurden, wenn in der Abfrage der Abfragestamm verwendet wird, sind einige Probleme aufgetreten:

  • Wenn eine definierende Abfrage einen Entitätstyp mit new { ... } in die Select-Methode projiziert, war für die Identifizierung dessen als Entität zusätzliche Arbeit erforderlich. Zudem sorgte dieses Vorgehen für Inkonsistenzen in Bezug darauf, wie EF Core nominale Typen in der Abfrage behandelt.
  • Bei relationalen Anbietern ist FromSql weiterhin erforderlich, um die SQL-Zeichenfolge im LINQ-Ausdrucksformat zu übergeben.

Zunächst wurden definierende Abfragen als clientseitige Sichten zur Verwendung mit In-Memory-Anbietern bei schlüssellosen Entitäten eingeführt (ähnlich wie bei Datenbanksichten in relationalen Datenbanken). Eine solche Definition erleichtert das Testen der Anwendung mit In-Memory-Datenbanken. Später wurden sie allgemein anwendbar, was zwar nützlich war, aber ein inkonsistentes und schwer verständliches Verhalten mit sich brachte. Daher haben wir uns entschieden, das Konzept zu vereinfachen. Wir stellen die LINQ-basierte definierende Abfrage nur noch für In-Memory-Anbieter bereit und behandeln sie anders. Weitere Informationen findest du in diesem Issue.

Gegenmaßnahmen

Verwenden Sie für relationale Anbieter die ToSqlQuery-Methode in OnModelCreating, und übergeben Sie eine SQL-Zeichenfolge zur Verwendung für den Entitätstyp. Verwenden Sie für den In-Memory-Anbieter die ToInMemoryQuery-Methode in OnModelCreating, und übergeben Sie eine LINQ-Abfrage zur Verwendung für den Entitätstyp.

Navigationen ohne Nullverweis werden von Abfragen nicht überschrieben

Nachverfolgung von Issue 2693

Altes Verhalten

In EF Core 3.1 wurden Verweisnavigationen, die frühzeitig mit Werten ungleich NULL initialisiert wurden, mitunter von Entitätsinstanzen aus der Datenbank überschrieben, und zwar unabhängig davon, ob Schlüsselwerte übereinstimmten oder nicht. In anderen Fällen hat EF Core 3.1 jedoch das Gegenteil bewirkt und den vorhandenen Wert ungleich NULL beibehalten.

Neues Verhalten

Ab EF Core 5.0 werden Verweisnavigationen ungleich NULL nicht mehr durch Instanzen überschrieben, die von einer Abfrage zurückgegeben werden.

Beachten Sie, dass die frühzeitige Initialisierung einer Sammlungsnavigation als leere Sammlung nach wie vor unterstützt wird.

Warum?

Die Initialisierung einer Verweisnavigationseigenschaft als „leere“ Entitätsinstanz führt zu einem uneindeutigen Zustand. Beispiel:

public class Blog
{
     public int Id { get; set; }
     public Author Author { get; set; ) = new Author();
}

Normalerweise erstellt eine Abfrage von Blogs und Autoren zunächst Blog-Instanzen. Dann werden die entsprechenden Author-Instanzen auf Grundlage der aus der Datenbank zurückgegebenen Daten festgelegt. In diesem Fall ist jedoch jede Blog.Author-Eigenschaft bereits als leere Author-Instanz initialisiert. Allerdings kann EF Core nicht wissen, dass diese Instanz „leer“ ist. Das Überschreiben dieser Instanz könnte also unbemerkt eine gültige Author-Instanz auslösen. Daher überschreibt EF Core 5.0 jetzt konsequent keine Navigation, die bereits initialisiert ist.

Dieses neue Verhalten stimmt in den meisten Fällen auch mit dem Verhalten von EF6 überein, obwohl wir bei Untersuchungen auch einige Fälle von Inkonsistenz in EF6 gefunden haben.

Gegenmaßnahmen

Wenn dieses Problem auftritt, besteht die Lösung darin, die vorzeitige Initialisierung der Verweisnavigationseigenschaften zu beenden.

ToView() wird von Migrationen anders verarbeitet

Nachverfolgung von Issue #2725

Altes Verhalten

Das Aufrufen von ToView(string) hat dazu geführt, dass Migrationen den Entitätstyp ignorieren und ihn einer Ansicht zuordnen.

Neues Verhalten

ToView(string) markiert den Entitätstyp nun als nicht einer Tabelle zugeordnet und ordnet ihn einer Ansicht zu. Dies führt dazu, dass bei der ersten Migration nach einem Upgrade zu EF Core 5 versucht wird, die Standardtabelle für diesen Entitätstyp zu löschen, da er nicht mehr ignoriert wird.

Warum?

EF Core ermöglicht es nun, dass ein Entitätstyp gleichzeitig sowohl einer Tabelle als auch einer Ansicht zugeordnet werden kann. ToView ist also kein gültiger Indikator dafür mehr, dass der Typ von Migrationen ignoriert werden soll.

Gegenmaßnahmen

Verwenden Sie den folgenden Code, um die zugeordnete Tabelle als von Migrationen ausgeschlossen zu markieren:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>().ToTable("UserView", t => t.ExcludeFromMigrations());
}

ToTable(null) markiert den Entitätstyp als nicht einer Tabelle zugeordnet

Nachverfolgung von Issue #21172

Altes Verhalten

ToTable(null) hat den Tabellennamen auf den Standardwert zurückgesetzt.

Neues Verhalten

ToTable(null) markiert den Entitätstyp nun als nicht einer Tabelle zugeordnet.

Warum?

EF Core ermöglicht es nun, dass ein Entitätstyp gleichzeitig sowohl einer Tabelle als auch einer Ansicht zugeordnet werden kann. ToTable(null) wird also verwendet, um anzugeben, dass der Typ keiner Tabelle zugeordnet ist.

Gegenmaßnahmen

Verwenden Sie den folgenden Code, um den Tabellennamen in den Standardwert zurückzusetzen, wenn keine Zuordnung zu einer Ansicht oder einer DbFunction-Klasse vorliegt:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>().Metadata.RemoveAnnotation(RelationalAnnotationNames.TableName);
}

Änderungen mit geringer Auswirkung

Die HasGeometricDimension-Methode wurde aus der SQLite NTS-Erweiterung entfernt.

Issue 14257

Altes Verhalten

Die HasGeometricDimension-Methode wurde dazu verwendet, zusätzliche Maße (Z und M) für Geometriespalten zu ermöglichen. Dies hat sich jedoch immer nur auf die Datenbankerstellung ausgewirkt. Das Angeben dieser Methode zum Abfragen von Werten mit zusätzlichen Maßen war nicht notwendig. Außerdem hat die Methode nicht ordnungsgemäß funktioniert, wenn Werte mit zusätzlichen Maßen eingefügt oder geändert wurden (siehe Issue 14257).

Neues Verhalten

Zum Ermöglichen des Einfügens und Änderns von Geometriewerten mit zusätzlichen Maßen (Z und M) muss das jeweilige Maß als Teil des Spaltentypnamens angegeben werden. Diese API entspricht eher dem zugrunde liegenden Verhalten der AddGeometryColumn-Funktion von SpatiaLite.

Warum?

Die Verwendung der HasGeometricDimension-Methode, nachdem das Maß im Spaltentyp festgelegt wurde, ist redundant und nicht notwendig. Daher wurde die gesamte HasGeometricDimension-Methode entfernt.

Gegenmaßnahmen

Verwenden Sie HasColumnType zum Festlegen der Maße:

modelBuilder.Entity<GeoEntity>(
    x =>
    {
        // Allow any GEOMETRY value with optional Z and M values
        x.Property(e => e.Geometry).HasColumnType("GEOMETRYZM");

        // Allow only POINT values with an optional Z value
        x.Property(e => e.Point).HasColumnType("POINTZ");
    });

Azure Cosmos DB: Der Partitionsschlüssel wird nun dem Primärschlüssel hinzugefügt

Tracking Issue 15289

Altes Verhalten

Die Partitionsschlüsseleigenschaft wurde nur dem alternativen Schlüssel hinzugefügt, der id enthält.

Neues Verhalten

Die Partitionsschlüsseleigenschaft wird gemäß Konvention jetzt auch dem Primärschlüssel hinzugefügt.

Warum?

Durch diese Änderung ist das Modell besser auf die Azure Cosmos DB-Semantik abgestimmt. Zudem verbessert sich dadurch die Leistung von Find und einigen Abfragen.

Gegenmaßnahmen

Um zu verhindern, dass die Partitionsschlüsseleigenschaft dem Primärschlüssel hinzugefügt wird, konfigurieren Sie sie in OnModelCreating.

modelBuilder.Entity<Blog>()
    .HasKey(b => b.Id);

Azure Cosmos DB: id Eigenschaft umbenannt in __id

Issue 17751

Altes Verhalten

Die der JSON-Eigenschaft id zugeordnete Schatteneigenschaft hatte ebenfalls den Namen id.

Neues Verhalten

Die gemäß Konvention erstellte Schatteneigenschaft trägt nun den Namen __id.

Warum?

Durch diese Änderung ist es weniger wahrscheinlich, dass die Eigenschaft id mit einer vorhandenen Eigenschaft des Entitätstyps kollidiert.

Gegenmaßnahmen

Wenn Sie zum Verhalten der Version 3.x zurückkehren möchten, konfigurieren Sie die Eigenschaft id in OnModelCreating.

modelBuilder.Entity<Blog>()
    .Property<string>("id")
    .ToJsonProperty("id");

Azure Cosmos DB: byte[] wird nun als Base64-Zeichenfolge statt als Zahlenarray gespeichert

Issue 17306

Altes Verhalten

Eigenschaften vom Typ „byte[]“ wurden als Zahlenarray gespeichert.

Neues Verhalten

Eigenschaften vom Typ „byte[]“ werden nun als Base64-Zeichenfolge gespeichert.

Warum?

Diese Darstellung von „byte[]“ entspricht eher den Erwartungen. Zudem handelt es sich hier um das Standardverhalten der wichtigen JSON-Serialisierungsbibliotheken.

Gegenmaßnahmen

Als Zahlenarrays gespeicherte, bereits vorhandene Daten werden weiterhin ordnungsgemäß abgefragt. Derzeit wird jedoch keine Möglichkeit unterstützt, das Einfügeverhalten zu ändern. Wenn Ihr Szenario durch diese Einschränkung blockiert wird, kommentieren Sie dieses Problem.

Azure Cosmos DB: GetPropertyName und SetPropertyName wurden umbenannt

Issue 17874

Altes Verhalten

Bisher wurden die Erweiterungsmethoden GetPropertyName und SetPropertyName genannt.

Neues Verhalten

Die alte API wurde entfernt, und es wurden die neuen Methoden GetJsonPropertyName und SetJsonPropertyName hinzugefügt.

Warum?

Durch diese Änderung wird die Mehrdeutigkeit um die Konfiguration durch diese Methoden beseitigt.

Gegenmaßnahmen

Verwenden Sie die neue API.

Wert-Generatoren werden aufgerufen, wenn der Entitätszustand von „Getrennt“ in „Unverändert“, „Aktualisiert“ oder „Gelöscht“ geändert wird

Tracking Issue 15289

Altes Verhalten

Wert-Generatoren wurden nur aufgerufen, wenn der Entitätszustand in „Hinzugefügt“ geändert wurde.

Neues Verhalten

Wert-Generatoren werden jetzt aufgerufen, wenn der Entitätszustand von „Getrennt“ in „Unverändert“, „Aktualisiert“ oder „Gelöscht“ geändert wird und die Eigenschaft die Standardwerte enthält.

Warum?

Diese Änderung war erforderlich, um die Verwendung von Eigenschaften zu verbessern, die nicht dauerhaft im Datenspeicher gespeichert sind und deren Wert immer auf dem Client generiert wird.

Gegenmaßnahmen

Weisen Sie der Eigenschaft vor der Änderung des Status einen anderen Wert als den Standardwert zu, um zu verhindern, dass der Wert-Generator aufgerufen wird.

IMigrationsModelDiffer verwendet jetzt IRelationalModel

Tracking Issue 20305

Altes Verhalten

Die IMigrationsModelDiffer-API wurde mithilfe von IModel definiert.

Neues Verhalten

Die IMigrationsModelDiffer-API verwendet jetzt IRelationalModel. Die Modellmomentaufnahme enthält jedoch weiterhin nur IModel, da dieser Code Teil der Anwendung ist und Entity Framework ihn nicht ohne einen größeren Breaking Change ändern kann.

Warum?

IRelationalModel ist eine neu hinzugefügte Darstellung des Datenbankschemas. Die Verwendung dieser Darstellung zum Ermitteln von Unterschieden ist schneller und präziser.

Gegenmaßnahmen

Verwenden Sie den folgenden Code, um das Modell von snapshot mit dem Modell von context zu vergleichen:

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

Eine Verbesserung dieser Funktion in Version 6.0 ist geplant (siehe 22031).

Diskriminatoren sind schreibgeschützt

Tracking Issue 21154

Altes Verhalten

Der Diskriminatorwert konnte vor dem Aufrufen von SaveChanges geändert werden.

Neues Verhalten

Im obigen Fall wird eine Ausnahme ausgelöst.

Warum?

EF erwartet nicht, dass der Entitätstyp geändert wird, während er noch nachverfolgt wird, sodass das Ändern des Diskriminatorwerts zu einem inkonsistenten Kontext führt. Dies hat möglicherweise ein unerwartetes Verhalten zur Folge.

Gegenmaßnahmen

Wenn eine Änderung des Diskriminatorwerts erforderlich ist und der Kontext direkt nach dem Aufruf von SaveChanges verworfen wird, kann der Diskriminator als änderbar festgelegt werden:

modelBuilder.Entity<BaseEntity>()
    .Property<string>("Discriminator")
    .Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Save);

Anbieterspezifische EF.Functions-Methoden werden für InMemory-Anbieter ausgelöst.

Issue 20294

Altes Verhalten

Anbieterspezifische EF.Functions-Methoden enthielten eine Implementierung für die Clientausführung, sodass sie für den InMemory-Anbieter ausgeführt werden konnten. EF.Functions.DateDiffDay ist beispielsweise eine SQL Server-spezifische Methode, die für InMemory-Anbieter galt.

Neues Verhalten

Anbieterspezifische Methoden wurden aktualisiert, sodass sie im Methodentext eine Ausnahme auslösen, um ihre Auswertung auf Clientseite zu blockieren.

Warum?

Anbieterspezifische Methoden sind einer Datenbankfunktion zugeordnet. Das Berechnungsergebnis der zugeordneten Datenbankfunktion kann auf Clientseite in LINQ nicht immer repliziert werden. Dies kann dazu führen, dass sich das Ergebnis von dem des Servers unterscheidet, wenn dieselbe Methode auf dem Client ausgeführt wird. Da diese Methoden in LINQ verwendet werden, um Übersetzungen in bestimmte Datenbankfunktionen durchzuführen, müssen sie nicht auf Clientseite ausgewertet werden. Da der InMemory-Anbieter eine andere Datenbank ist, sind die Methoden für diesen Anbieter nicht verfügbar. Wenn Sie versuchen, sie für den InMemory-Anbieter oder einen anderen Anbieter auszuführen, der diese Methoden nicht übersetzt, wird eine Ausnahme ausgelöst.

Gegenmaßnahmen

Da es keine Möglichkeit gibt, das Verhalten von Datenbankfunktionen exakt zu imitieren, sollten Sie die Abfragen, die diese Methoden enthalten, mit demselben Datenbanktyp testen, der auch in der Produktionsumgebung verwendet wird.

IndexBuilder.HasName ist mittlerweile veraltet

Nachverfolgung von Issue 21089

Altes Verhalten

Bisher konnte nur ein Index für eine bestimmte Gruppe von Eigenschaften definiert werden. Der Datenbankname eines Indexes wurde mithilfe von IndexBuilder.HasName konfiguriert.

Neues Verhalten

Für dieselbe Gruppe oder dieselben Eigenschaften sind jetzt mehrere Indizes zulässig. Diese Indizes unterscheiden sich nun durch einen Namen im Modell. Gemäß der Konvention wird der Modellname als Datenbankname verwendet. Er kann jedoch auch unabhängig mit HasDatabaseName konfiguriert werden.

Warum?

In Zukunft möchten wir sowohl aufsteigende als auch absteigende Indizes oder Indizes mit unterschiedlichen Sortierungen für denselben Satz von Eigenschaften aktivieren. Diese Änderung ist ein weiterer Schritt in diese Richtung.

Gegenmaßnahmen

Sämtlicher Code, der zuvor IndexBuilder.HasName aufgerufen hat, sollte so aktualisiert werden, dass stattdessen HasDatabaseName aufgerufen wird.

Wenn das Projekt Migrationen enthält, die vor EF Core Version 2.0.0 generiert wurden, können Sie die Warnung in diesen Dateien problemlos ignorieren und unterdrücken, indem Sie #pragma warning disable 612, 618 hinzufügen.

Ein Pluralizer ist nun für den Gerüstbau für Modelle mit Reverse Engineering enthalten

Nachverfolgung von Issue 11160

Altes Verhalten

Bislang mussten Sie beim Gerüstbau für einen Datenbankkontext und Entitätstypen durch Reverse Engineering eines Datenbankschemas ein separates Pluralizer-Paket installieren, um DbSet- und Sammlungsnavigationsnamen in die Pluralform und Tabellennamen in die Singularform umzuwandeln.

Neues Verhalten

EF Core enthält jetzt einen Pluarlizer, der die Humanizer-Bibliothek verwendet. Dies ist dieselbe Bibliothek, die Visual Studio verwendet, um Variablennamen zu empfehlen.

Warum?

Die Verwendung von Pluralformen von Wörtern für Sammlungseigenschaften und Singularformen für Typen und Verweiseigenschaften ist in .NET idiomatisch.

Gegenmaßnahmen

Um den Pluralizer zu deaktivieren, verwenden Sie die Option --no-pluralize auf dotnet ef dbcontext scaffold oder den -NoPluralize-Switch auf Scaffold-DbContext.

INavigationBase ersetzt INavigation in einigen APIs zur Unterstützung überspringender Navigationen

Nachverfolgung von Issue 2568

Altes Verhalten

Bis Version 5.0 unterstützte EF Core nur eine Form der Navigationseigenschaft, die durch die INavigation-Schnittstelle dargestellt wird.

Neues Verhalten

EF Core 5.0 führt m:n-Beziehungen ein, die „überspringende Navigationen“ verwenden. Diese werden durch die ISkipNavigation-Schnittstelle dargestellt, und der größte Teil der Funktionalität von INavigation wurde auf die gemeinsame Basisschnittstelle INavigationBase verlagert.

Warum?

Die meisten Funktionen sind bei normalen und überspringenden Navigationen identisch. Allerdings haben überspringende Navigationen eine andere Beziehung zu Fremdschlüsseln als normale Navigationen, da sich die beteiligten Fremdschlüssel nicht direkt an beiden Enden der Beziehung befinden, sondern in der JOIN-Entität.

Gegenmaßnahmen

In vielen Fällen können Anwendungen ohne weitere Änderungen zur Verwendung der neuen Basisschnittstelle übergehen. In Fällen jedoch, in denen die Navigation für den Zugriff auf Fremdschlüsseleigenschaften verwendet wird, sollte der Code der Anwendung entweder nur auf normale Navigationen beschränkt oder so aktualisiert werden, dass er sowohl bei normalen als auch bei überspringenden Navigationen das Richtige tut.

Einige Abfragen mit korrelierter Sammlung, die ebenfalls Distinct oderGroupBy verwenden, werden nicht mehr unterstützt

Nachverfolgung von Issue 15873

Altes Verhalten

Zuvor haben wir die Ausführung von Abfragen mit korrelierten Sammlungen, gefolgt von GroupBy, sowie einige Abfragen mit Distinct erlaubt.

Beispiel für GroupBy:

context.Parents
    .Select(p => p.Children
        .GroupBy(c => c.School)
        .Select(g => g.Key))

Beispiel für Distinct: insbesondere Distinct-Abfragen, bei denen die innere Sammlungsprojektion nicht den Primärschlüssel enthält:

context.Parents
    .Select(p => p.Children
        .Select(c => c.School)
        .Distinct())

Diese Abfragen konnten falsche Ergebnisse liefern, wenn die innere Sammlung Duplikate enthielt, funktionierten aber einwandfrei, wenn alle Elemente in der inneren Sammlung eindeutig waren.

Neues Verhalten

Diese Abfragen werden nicht mehr unterstützt. Es wird eine Ausnahme ausgelöst, die darauf hinweist, dass wir nicht genügend Informationen haben, um die Ergebnisse ordnungsgemäß zu erstellen.

Hintergründe

Für Szenarien mit korrelierten Sammlungen müssen wir den Primärschlüssel der Entitäten kennen, um die Sammlungsentitäten dem richtigen übergeordneten Element zuweisen zu können. Wenn die innere Sammlung GroupBy oder Distinct nicht verwendet, kann der fehlende Primärschlüssel einfach zur Projektion hinzugefügt werden. Im Falle von GroupBy und Distinct ist dies jedoch nicht möglich, weil es das Ergebnis des Vorgangs GroupBy oder Distinct ändern würde.

Gegenmaßnahmen

Schreiben Sie die Abfrage so um, dass die Vorgänge GroupBy oder Distinct nicht auf die innere Sammlung angewendet werden. Führen Sie diese Vorgänge stattdessen auf dem Client aus.

context.Parents
    .Select(p => p.Children.Select(c => c.School))
    .ToList()
    .Select(x => x.GroupBy(c => c).Select(g => g.Key))
context.Parents
    .Select(p => p.Children.Select(c => c.School))
    .ToList()
    .Select(x => x.Distinct())

Die Verwendung einer Sammlung abfragbarer Typen in der Projektion wird nicht unterstützt

Nachverfolgung von Issue 16314

Altes Verhalten

Bislang war es in einigen Fällen möglich, eine Sammlung eines abfragbaren Typs innerhalb der Projektion zu verwenden, z. B. als Argument für einen List<T>-Konstruktor:

context.Blogs
    .Select(b => new List<Post>(context.Posts.Where(p => p.BlogId == b.Id)))

Neues Verhalten

Diese Abfragen werden nicht mehr unterstützt. Eine Ausnahme wird ausgelöst, die darauf hinweist, dass wir kein Objekt des abfragbaren Typs erstellen können, und vorschlägt, wie dies korrigiert werden könnte.

Hintergründe

Wir können ein Objekt eines abfragbaren Typs nicht materialisieren. Daher würde es stattdessen automatisch mit dem Typ List<T> erstellt werden. Dies führte oft zu einer Ausnahme aufgrund nicht übereinstimmender Typen, was nicht sehr klar wurde und für einige Benutzer überraschend sein konnte. Wir haben uns entschieden, das Muster zu erkennen und eine aussagekräftigere Ausnahme auszulösen.

Gegenmaßnahmen

Fügen Sie hinter dem abfragbaren Objekt in der Projektion einen Aufruf von ToList() hinzu:

context.Blogs.Select(b => context.Posts.Where(p => p.BlogId == b.Id).ToList())