Freigeben über


Breaking Changes in EF Core 9 (EF9)

Auf dieser Seite werden API-Änderungen und Behavior Changes dokumentiert, die bei einem Update von EF Core 8 auf EF Core 9 zu Problemen mit bestehenden Anwendungen führen können. Überprüfen Sie frühere grundlegende Änderungen, wenn sie von einer früheren Version von EF Core aktualisiert werden:

Zielframework

EF Core 9 zielt auf .NET 8 ab. Dies bedeutet, dass vorhandene Anwendungen, die auf .NET 8 abzielen, dies weiterhin tun können. Anwendungen für ältere .NET, .NET Core und .NET Framework-Versionen müssen auf .NET 8 oder .NET 9 abzielen, um EF Core 9 zu verwenden.

Zusammenfassung

Hinweis

Wenn Sie Azure Cosmos DB verwenden, lesen Sie den separaten Abschnitt untenstehend zu Azure Cosmos DB-Änderungen.

Wichtige Änderung Auswirkung
Eine Ausnahme wird ausgelöst, wenn beim Anwenden von Migrationen ausstehende Modelländerungen vorhanden sind. Hoch
Eine Ausnahme wird ausgelöst, wenn Migrationen in einer expliziten Transaktion angewendet werden. Hoch
Microsoft.EntityFrameworkCore.Design bei Verwendung von EF-Tools nicht gefunden Medium
EF.Functions.Unhex() gibt jetzt byte[]? zurück Niedrig
Kompilierte Modelle verweisen jetzt direkt auf Wertkonvertermethoden Niedrig
Die Arity der NULL-Zulässigkeitsargumente von SqlFunctionExpression wurde validiert Niedrig
ToString()-Methode gibt jetzt für null-Instanzen eine leere Zeichenfolge zurück Niedrig
Freigegebene Framework-Abhängigkeiten wurden auf 9.0.x aktualisiert Niedrig
EF-Tools unterstützen .NET Framework-Projekte nicht mehr Niedrig

Änderungen mit hoher Auswirkung

Eine Ausnahme wird ausgelöst, wenn Migrationen angewendet werden und ausstehende Modelländerungen vorhanden sind.

Nachverfolgung von Issue #33732

Altes Verhalten

Wenn das Modell im Vergleich zur letzten Migration ausstehende Änderungen aufweist, werden sie nicht mit den restlichen Migrationen angewendet, wenn Migrate aufgerufen wird.

Neues Verhalten

Ab EF Core 9.0 wird eine Ausnahme ausgelöst, wenn das Modell im Vergleich zur letzten Migration ausstehende Änderungen aufweist und dotnet ef database update, Migrate oder MigrateAsync aufgerufen wird.

Das Modell für den Kontext „DbContext“ hat ausstehende Änderungen. Fügen Sie eine neue Migration hinzu, bevor Sie die Datenbank aktualisieren. Diese Ausnahme lässt sich unterdrücken oder protokollieren, indem Sie die Ereignis-ID „RelationalEventId.PendingModelChangesWarning“ an die Methode „ConfigureWarnings“ in „DbContext.OnConfiguring“ oder „AddDbContext“ übergeben.

Warum?

Nach Modelländerungen zu vergessen, eine neue Migration hinzuzufügen, ist ein häufiger Fehler, der in einigen Fällen schwer zu diagnostizieren sein kann. Die neue Ausnahme stellt sicher, dass das Modell der App der Datenbank entspricht, nachdem die Migrationen angewendet wurden.

Gegenmaßnahmen

Es gibt mehrere häufige Situationen, in denen diese Ausnahme ausgelöst werden kann:

  • Es gibt überhaupt keine Migrationen. Dies ist üblich, wenn die Datenbank auf andere Wege aktualisiert wird.

    • Risikominderung: Wenn Sie keine Migrationen für die Verwaltung des Datenbankschemas verwenden möchten, entfernen Sie den Migrate- oder MigrateAsync-Aufruf, andernfalls fügen Sie eine Migration hinzu.
  • Es gibt mindestens eine Migration, aber der Modellschnappschuss fehlt. Dies ist üblich für manuell erstellte Migrationen.

    • Risikominderung: Fügen Sie eine neue Migration mithilfe von EF-Tools hinzu. Dadurch wird die Modellmomentaufnahme aktualisiert.
  • Das Modell wurde vom Entwickler nicht geändert, aber es ist in einer nicht deterministischen Weise integriert, die dazu führt, dass EF sie als geändert erkennt. Dies ist üblich, wenn new DateTime(), DateTime.Now, DateTime.UtcNowoder Guid.NewGuid() in Objekten verwendet werden, die an HasData bereitgestellt werden.

    • Risikominderung: Fügen Sie eine neue Migration hinzu, überprüfen Sie deren Inhalt, um die Ursache zu finden, und ersetzen Sie die dynamischen Daten durch einen statischen, hartcodierten Wert im Modell. Die Migration sollte neu erstellt werden, nachdem das Modell korrigiert wurde. Wenn dynamische Daten für das Seeding verwendet werden müssen, sollten Sie das neue Seedingmuster anstelle von HasData verwenden.
  • Die letzte Migration wurde für einen anderen Anbieter erstellt als der, der zum Anwenden der Migrationen verwendet wurde.

    • Risikominderung: Dies ist ein Szenario, das nicht unterstützt wird. Die Warnung kann mithilfe des folgenden Codeausschnitts unterdrückt werden, dieses Szenario funktioniert jedoch wahrscheinlich nicht mehr in einer zukünftigen EF Core-Release. Die empfohlene Lösung ist , um einen separaten Satz von Migrationen für jeden Anbieter zu generieren.
  • Die Migrationen werden generiert, geändert oder dynamisch ausgewählt, indem einige der EF-Dienste ersetzt werden.

    • Risikominderung: Die Warnung ist in diesem Fall ein Fehlalarm und sollte unterdrückt werden.
      options.ConfigureWarnings(w => w.Ignore(Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.PendingModelChangesWarning))
  • Sie verwenden ASP.NET Core Identität und ändern Optionen, die sich auf das Modell auswirken, z. B.:

    .AddDefaultIdentity<ApplicationUser>(options =>
        {
            options.Stores.SchemaVersion = IdentitySchemaVersions.Version2;
            options.Stores.MaxLengthForKeys = 256;
            options.SignIn.RequireConfirmedAccount = false;
        })
    
    • Entschärfung: Um sicherzustellen, dass die Optionen konsistent angewendet werden, muss die App beim Ausführen der EF-Tools als Startprojekt angegeben werden oder alternativ im Projekt implementiert werden, IDesignTimeDbContextFactory das folgendes DbContextenthält:

      public class DatabaseContextDesignTimeFactory : IDesignTimeDbContextFactory<DatabaseContext>
      {
          public DatabaseContext CreateDbContext(string[] args)
          {
              var services = new ServiceCollection();
              AddIdentity(services);
              var serviceProvider = services.BuildServiceProvider();
              var optionsBuilder = new DbContextOptionsBuilder<DatabaseContext>();
              optionsBuilder.UseApplicationServiceProvider(serviceProvider);
              optionsBuilder.UseSqlServer();
              return new DatabaseContext(optionsBuilder.Options);
          }
      
          public static IServiceCollection AddIdentity(IServiceCollection services)
          {
              services.AddDefaultIdentity<ApplicationUser>(options =>
                  {
                      options.Stores.SchemaVersion = IdentitySchemaVersions.Version2;
                      options.Stores.MaxLengthForKeys = 256;
                      options.SignIn.RequireConfirmedAccount = false;
                  })
                  .AddRoles<IdentityRole>()
                  .AddEntityFrameworkStores<DatabaseContext>();
      
              return services;
          }
      }
      

Wenn Ihr Szenario zu keinem der oben genannten Fälle passt und das Hinzufügen einer neuen Migration jedes Mal die gleiche Migration oder eine leere Migration erstellt und die Ausnahme weiterhin ausgelöst wird, erstellen Sie ein kleines Repro-Projekt und geben sie es dem EF-Team in einem neuen Problem weiter.

Eine Ausnahme wird ausgelöst, wenn Migrationen in einer expliziten Transaktion angewendet werden.

Nachverfolgung von Issue 17578

Altes Verhalten

Um Migrationen robust anzuwenden, wurde häufig das folgende Muster verwendet:

await dbContext.Database.CreateExecutionStrategy().ExecuteAsync(async () =>
{
    await using var transaction = await dbContext.Database.BeginTransactionAsync(cancellationToken);
    await dbContext.Database.MigrateAsync(cancellationToken);
    await transaction.CommitAsync(cancellationToken);
});

Neues Verhalten

Ab EF Core 9.0 starten Migrate- und MigrateAsync-Aufrufe eine Transaktion und führen die Befehle mithilfe einer ExecutionStrategy aus, und wenn ihre App das obige Muster verwendet, wird eine Ausnahme ausgelöst:

Für die Warnung 'Microsoft.EntityFrameworkCore.Migrations.MigrationsUserTransactionWarning' wurde ein Fehler generiert: Eine Transaktion wurde vor dem Anwenden von Migrationen gestartet. Dadurch wird verhindert, dass eine Datenbanksperre erworben wird, und daher wird die Datenbank nicht vor gleichzeitig ausgeführten Migrationsanwendungen geschützt. Die Transaktionen und die Ausführungsstrategie werden bereits wie erforderlich von EF verwaltet. Entfernen Sie die externe Transaktion. Diese Ausnahme kann unterdrückt oder protokolliert werden, indem die Ereignis-ID „RelationalEventId.MigrationsUserTransactionWarning“ an die Methode „ConfigureWarnings“ in „DbContext.OnConfiguring“ oder „AddDbContext“ übergeben wird.

Warum?

Eine explizite Transaktion verhindert, dass eine Datenbanksperre erworben wird. Daher bleibt die Datenbank nicht vor gleichzeitigen Migrationsanwendungen geschützt. Außerdem schränkt dies EF in der Art und Weise ein, wie es die Transaktionen intern verwalten kann.

Gegenmaßnahmen

Wenn nur ein Datenbankaufruf innerhalb der Transaktion vorhanden ist, entfernen Sie die externe Transaktion und ExecutionStrategy:

await dbContext.Database.MigrateAsync(cancellationToken);

Andernfalls, wenn Ihr Szenario eine explizite Transaktion erfordert und Sie einen anderen Mechanismus zum Verhindern der gleichzeitigen Migrationsanwendung haben, ignorieren Sie die Warnung:

options.ConfigureWarnings(w => w.Ignore(RelationalEventId.MigrationsUserTransactionWarning))

Änderungen mit mittlerer Auswirkung

Microsoft.EntityFrameworkCore.Design bei Verwendung von EF-Tools nicht gefunden

Nachverfolgung von Issue 35265

Altes Verhalten

Vorab mussten die EF-Tools Microsoft.EntityFrameworkCore.Design wie folgt referenziert werden.

    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="*.0.0">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>

Neues Verhalten

Beginnend mit .NET SDK 9.0.200 wird eine Ausnahme ausgelöst, wenn ein EF-Tool aufgerufen wird:

Datei oder Assembly "Microsoft.EntityFrameworkCore.Design, Culture=neutral, PublicKeyToken=null" konnte nicht geladen werden. Die angegebene Datei wurde nicht gefunden.

Warum?

EF-Tools basieren auf einem nicht dokumentierten Verhalten des .NET SDK, das dazu führte, dass private Ressourcen in die generierte .deps.jsonDatei aufgenommen wurden. Dies wurde in sdk#45259 behoben. Leider erfüllt die EF-Änderung zur Berücksichtigung dessen nicht die Wartungsanforderungen für EF 9.0.x, sodass sie in EF 10 behoben wird.

Gegenmaßnahmen

Als Problemumgehung vor der Veröffentlichung von EF 10 können Sie den Design-Assemblyverweis als veröffentlichungsfähig kennzeichnen:

    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.1">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <Publish>true</Publish>
    </PackageReference>

Dies schließt sie in die generierte .deps.json-Datei ein, hat jedoch einen Nebeneffekt, Microsoft.EntityFrameworkCore.Design.dll in die Ausgabe- und Veröffentlichungsordner zu kopieren.

Änderungen mit geringer Auswirkung

EF.Functions.Unhex() gibt jetzt byte[]? zurück

Nachverfolgung von Issue 33864

Altes Verhalten

Die EF.Functions.Unhex() Funktion wurde zuvor mit Anmerkungen versehen, um byte[] zurückzugeben.

Neues Verhalten

Ab EF Core 9.0 wird Unhex() nun kommentiert, um byte[]? zurückzugeben.

Warum?

Unhex() wird in die SQLite-Funktion unhex übersetzt, die bei ungültigen Eingaben NULL zurückgibt. Infolgedessen gab Unhex() für diese Fälle null zurück, was einen Verstoß gegen die Anmerkung darstellt.

Gegenmaßnahmen

Wenn Sie sicher sind, dass der an Unhex() übergebene Textinhalt eine gültige hexadezimale Zeichenkette darstellt, können Sie einfach den Null-Forgiving-Operator als Zusicherung hinzufügen, dass der Aufruf niemals Null zurückgibt:

var binaryData = await context.Blogs.Select(b => EF.Functions.Unhex(b.HexString)!).ToListAsync();

Fügen Sie andernfalls Laufzeitüberprüfungen auf Nullwerte für den Rückgabewert von Unhex() hinzu.

Kompilierte Modelle verweisen jetzt direkt auf Wertkonvertermethoden

Tracking-Issue Nr. 35033

Altes Verhalten

Bei Verwendung von Wertkonvertern mit kompilierten Modellen (mithilfe von dotnet ef dbcontext optimize) verwies EF auf den Konvertertyp, und alles funktionierte ordnungsgemäß.

public sealed class BooleanToCharConverter() : ValueConverter<bool, char>(v => ConvertToChar(v), v => ConvertToBoolean(v))
{
    public static readonly BooleanToCharConverter Default = new();

    private static char ConvertToChar(bool value) // Private method
        => value ? 'Y' : 'N';

    private static bool ConvertToBoolean(char value) // Private method
        => value == 'Y';
}

Neues Verhalten

Ab EF Core 9.0 generiert EF Code, der direkt auf die Konvertierungsmethoden verweist. Wenn diese Methoden privat sind, schlägt die Kompilierung fehl.

Warum?

Diese Änderung war erforderlich, um NativeAOT zu unterstützen.

Gegenmaßnahmen

Machen Sie die Methoden, auf die von Wertkonvertern verwiesen wird, öffentlich oder intern statt privat.

Die Anzahl der NULL-Zulässigkeitsargumente von SqlFunctionExpression wurde validiert.

Nachverfolgung von Issue 33852

Altes Verhalten

Zuvor war es möglich, eine SqlFunctionExpression mit einer anderen Anzahl von Argumenten und Argumenten zur Propagierung der Null-Zulässigkeit zu erstellen.

Neues Verhalten

Ab EF Core 9.0 löst EF jetzt aus, wenn die Anzahl von Argumenten und NULL-Zulässigkeitsverteilungsargumenten nicht übereinstimmen.

Warum?

Das Fehlen einer übereinstimmenden Anzahl von Argumenten und Argumenten zur Verbreitung der Null-Zulässigkeit kann zu unerwartetem Verhalten führen.

Gegenmaßnahmen

Stellen Sie sicher, dass die argumentsPropagateNullability dieselbe Anzahl von Elementen wie die arguments aufweist. Verwenden Sie im Zweifelsfall false als Nullwert-Argument.

ToString()-Methode gibt jetzt für null-Instanzen eine leere Zeichenfolge zurück

Nachverfolgung von Issue 33941

Altes Verhalten

Zuvor wurden von EF inkonsistente Ergebnisse für die ToString()-Methode zurückgegeben, wenn der Argumentwert null war. So wurde beispielsweise bei ToString() für die Eigenschaft bool? mit dem Wert null der Wert null zurückgegeben, aber bei Ausdrücken ohne die Eigenschaft bool?, deren Wert null war, wurde True zurückgegeben. Das Verhalten war auch für andere Datentypen inkonsistent. So wurde beispielsweise bei ToString() für die null-Wertenumeration eine leere Zeichenfolge zurückgegeben.

Neues Verhalten

Ab EF Core 9.0 gibt die Methode ToString() nun konsistent in allen Fällen eine leere Zeichenfolge zurück, wenn der Argumentwert null ist.

Warum?

Das alte Verhalten war bei unterschiedlichen Datentypen und in unterschiedlichen Situationen inkonsistent und nicht auf das Verhalten von C# abgestimmt.

Gegenmaßnahmen

Wenn Sie zum alten Verhalten zurückkehren möchten, schreiben Sie die Abfrage entsprechend um:

var newBehavior = context.Entity.Select(x => x.NullableBool.ToString());
var oldBehavior = context.Entity.Select(x => x.NullableBool == null ? null : x.NullableBool.ToString());

Abhängigkeiten des gemeinsamen Frameworks wurden auf 9.0.x aktualisiert

Altes Verhalten

Apps, die das Microsoft.NET.Sdk.Web SDK verwenden und auf net8.0 abzielen, lösen Pakete wie System.Text.Json, Microsoft.Extensions.Caching.Memory, Microsoft.Extensions.Configuration.Abstractions, Microsoft.Extensions.Logging und Microsoft.Extensions.DependencyModel aus dem freigegebenen Framework auf, sodass diese Assemblys normalerweise nicht mit der App bereitgestellt werden.

Neues Verhalten

Während EF Core 9.0 weiterhin net8.0 unterstützt, verweist es jetzt auf die 9.0.x-Versionen von System.Text.Json, Microsoft.Extensions.Caching.Memory, Microsoft.Extensions.Configuration.Abstractions, Microsoft.Extensions.Logging und Microsoft.Extensions.DependencyModel. Apps, die für net8.0 konzipiert sind, können das freigegebene Framework nicht nutzen, um die Bereitstellung dieser Assemblys zu vermeiden.

Warum?

Die entsprechenden Abhängigkeitsversionen enthalten die neuesten Sicherheitskorrekturen, und ihre Verwendung vereinfacht das Wartungsmodell für EF Core.

Gegenmaßnahmen

Richten Sie Ihre App auf net9.0 aus, um das vorherige Verhalten zu erhalten.

EF-Tools unterstützen .NET Framework-Projekte nicht mehr

Verfolgungsproblem Nr. 37745

Altes Verhalten

Zuvor haben die EF Core-Tools (dotnet-ef CLI und Paket-Manager Konsolentools) mit Projekten für .NET Framework gearbeitet.

Neues Verhalten

Ab EF Core 9.0 funktionieren die EF Core-Tools nicht mehr mit Projekten für .NET Framework. Die Tools erzeugen einen Fehler, wenn das Startprojekt auf .NET Framework ausgerichtet ist.

Warum?

Die aktuelle Version der EF Core-Tools funktioniert mit allen unterstützten EF Core-Versionen, und es gibt keine unterstützten EF Core-Versionen mehr, die in .NET Framework funktionieren.

Gegenmaßnahmen

Aktualisieren Sie Ihr Projekt auf .NET (z. B. .NET 8 oder höher). Wenn Ihr Projekt derzeit auf .NET Framework ausgerichtet ist, finden Sie im Leitfaden zum Porting Informationen zum Migrieren zu .NET.

Azure Cosmos DB änderungen unterbrechen

Umfassende Arbeiten wurden geleistet, um den Azure Cosmos DB-Anbieter in Version 9.0 zu verbessern. Die Änderungen umfassen eine Reihe von Änderungen mit hoher Auswirkung; Wenn Sie ein Upgrade einer vorhandenen Anwendung durchführen, lesen Sie bitte Folgendes sorgfältig.

Wichtige Änderung Auswirkung
Die Diskriminatoreigenschaft wird jetzt $type anstelle von Discriminator genannt Hoch
Die id Eigenschaft enthält standardmäßig nicht mehr den Diskriminator Hoch
Die JSON id Eigenschaft wird dem Schlüssel zugeordnet Hoch
Sync-E/A über den Azure Cosmos DB-Anbieter wird nicht mehr unterstützt Medium
SQL-Abfragen müssen jetzt JSON-Werte direkt projizieren Medium
Nicht definierte Ergebnisse werden jetzt automatisch aus Abfrageergebnissen gefiltert Medium
Falsch übersetzte Abfragen werden nicht mehr übersetzt Medium
HasIndex wird jetzt ausgelöst, anstatt ignoriert zu werden Niedrig
IncludeRootDiscriminatorInJsonId wurde nach 9.0.0-rc.2 in HasRootDiscriminatorInJsonId umbenannt Niedrig
Die referenzierte Newtonsoft.Json-Version wurde von 10.0.2 auf 13.0.1 aktualisiert. Niedrig

Änderungen mit hoher Auswirkung

Die Diskriminatoreigenschaft wird jetzt $type anstelle von Discriminator genannt

Verfolgungsproblem #34269

Altes Verhalten

EF fügt JSON-Dokumenten automatisch eine Diskriminatoreigenschaft hinzu, um den Entitätstyp zu identifizieren, den das Dokument darstellt. In früheren Versionen von EF wurde diese JSON-Eigenschaft standardmäßig Discriminator genannt.

Neues Verhalten

Ab EF Core 9.0 wird die Diskriminatoreigenschaft jetzt standardmäßig $type genannt. Wenn Sie dokumente in Azure Cosmos DB aus früheren Versionen von EF haben, verwenden diese die alte Discriminator Benennung, und nach dem Upgrade auf EF 9.0 schlagen Abfragen für diese Dokumente fehl.

Warum?

Eine neue JSON-Praxis verwendet eine $type Eigenschaft in Szenarien, in denen der Typ eines Dokuments identifiziert werden muss. Beispielsweise unterstützt .NET System.Text.Json auch Polymorphismus, wobei $type als Standardnamen der Diskriminatoreigenschaft (docs) verwendet wird. Um den Rest des Ökosystems auszurichten und die Zusammenarbeit mit externen Tools zu vereinfachen, wurde die Standardeinstellung geändert.

Gegenmaßnahmen

Die einfachste Abhilfemaßnahme besteht darin, den Namen der Diskriminatoreigenschaft einfach als Discriminator zu konfigurieren, wie zuvor mit HasDiscriminator.

modelBuilder.Entity<Session>().HasDiscriminator<string>("Discriminator");

Dadurch verhält sich EF für alle Entitätstypen auf oberster Ebene genau wie zuvor.

Wenn Sie möchten, können Sie auch alle Ihre Dokumente so aktualisieren, dass sie die neue $type Benennung verwenden.

Die id Eigenschaft enthält jetzt standardmäßig nur die EF-Schlüsseleigenschaft.

Verfolgungs-Token #34179

Altes Verhalten

Zuvor hat EF den Diskriminatorwert Ihres Entitätstyps in die id Eigenschaft des Dokuments eingefügt. Wenn Sie beispielsweise einen Entitätstyp Blog mit einer Id Eigenschaft mit 8 gespeichert haben, würde die JSON-Eigenschaft id enthalten Blog|8.

Neues Verhalten

Ab EF Core 9.0 enthält die JSON-Eigenschaft id nicht mehr den Diskriminatorwert, sondern nur noch den Wert Ihrer Schlüsseleigenschaft. Im obigen Beispiel wäre die JSON-Eigenschaft id einfach 8 sein. Wenn Sie dokumente in Azure Cosmos DB aus früheren Versionen von EF haben, weisen diese den Diskriminatorwert in der JSON-id-Eigenschaft auf, und nach dem Upgrade auf EF 9.0 schlagen Abfragen für diese Dokumente fehl.

Warum?

Da die JSON-Eigenschaft id eindeutig sein muss, wurde früher der Diskriminator hinzugefügt, um die Existenz unterschiedlicher Entitäten mit dem gleichen Schlüsselwert zu ermöglichen. Dadurch konnten beispielsweise innerhalb des gleichen Containers und der gleichen Partition ein Blog und ein Post mit einer Id-Eigenschaft vorhanden sein, die den Wert 8 enthält. Dies passte besser zu Datenmodellierungsmustern relationaler Datenbanken, bei denen jeder Entitätstyp einer eigenen Tabelle zugeordnet ist und somit über einen eigenen Schlüsselraum verfügt.

EF 9.0 hat die Zuordnung im Allgemeinen geändert, um sich stärker an gemeinsame Azure Cosmos DB NoSQL Praktiken und Erwartungen auszurichten, anstatt den Erwartungen der Benutzer, die aus relationalen Datenbanken stammen, zu entsprechen. Darüber hinaus hat die Berücksichtigung des Diskriminatorwerts in der eigenschaft id es für externe Tools und Systeme schwieriger, mit EF-generierten JSON-Dokumenten zu interagieren; Solche externen Systeme kennen die EF-Diskriminatorwerte nicht allgemein, die standardmäßig von .NET Typen abgeleitet sind.

Gegenmaßnahmen

Die einfachste Entschärfung besteht darin, EF so zu konfigurieren, dass es den Diskriminator in die JSON-Eigenschaft id einschließt, wie zuvor HasDiscriminatorInJsonId verwendet. Zu diesem Zweck wurde eine neue Konfigurationsoption eingeführt:

modelBuilder.Entity<Session>().HasDiscriminatorInJsonId();

Dadurch verhält sich EF für alle Entitätstypen auf oberster Ebene genau wie zuvor.

Wenn Sie möchten, können Sie auch alle Ihre Dokumente aktualisieren, um ihre JSON-Eigenschaft id neu zu schreiben. Beachten Sie, dass dies nur möglich ist, wenn Entitäten unterschiedlicher Typen nicht den gleichen ID-Wert innerhalb desselben Containers gemeinsam verwenden.

Die JSON-id-Eigenschaft wird dem Schlüssel zugeordnet.

Verfolgungs-Token #34179

Altes Verhalten

Zuvor hat EF eine Schatteneigenschaft erstellt, die der JSON-id-Eigenschaft zugeordnet ist, es sei denn, einer der Eigenschaften wurde explizit id zugeordnet.

Neues Verhalten

Ab EF Core 9 wird die Schlüsseleigenschaft nach Möglichkeit der JSON-id-Eigenschaft zugeordnet. Dies bedeutet, dass die Schlüsseleigenschaft nicht mehr unter einem anderen Namen mit demselben Wert beibehalten wird, sodass Nicht-EF-Code, der die Dokumente verwendet und diese Eigenschaft nutzt, nicht mehr korrekt funktioniert.

Warum?

EF 9.0 hat die Zuordnung im Allgemeinen geändert, um sich stärker an gemeinsame Azure Cosmos DB NoSQL Praktiken und Erwartungen auszurichten. Und es ist nicht üblich, den Schlüsselwert zweimal im Dokument zu speichern.

Gegenmaßnahmen

Wenn Sie das EF Core 8-Verhalten beibehalten möchten, besteht die einfachste Entschärfung darin, eine neue Konfigurationsoption zu verwenden HasShadowId, die zu diesem Zweck eingeführt wurde:

modelBuilder.Entity<Session>().HasShadowId();

Dadurch verhält sich EF für alle Entitätstypen auf oberster Ebene genau wie zuvor. Sie können sie auch auf alle Entitätstypen im Modell mit einem Aufruf anwenden:HasShadowIds

modelBuilder.HasShadowIds();

Änderungen mit mittlerer Auswirkung

Die Synchronisierung von E/A über den Azure Cosmos DB-Anbieter wird nicht mehr unterstützt.

Nachverfolgung von Issue 32563

Altes Verhalten

Das Aufrufen synchroner Methoden wie ToList oder SaveChanges würde dazu führen, dass EF Core synchron mit .GetAwaiter().GetResult() blockiert wird, wenn asynchrone Aufrufe für das Azure Cosmos DB SDK ausgeführt werden. Dies kann zu Deadlock führen.

Neues Verhalten

Ab EF Core 9.0 wird EF jetzt standardmäßig ausgelöst, wenn versucht wird, synchronen E/A zu verwenden. Die Ausnahmemeldung lautet "Azure Cosmos DB unterstützt keine synchrone E/A. Stellen Sie sicher, dass Sie nur asynchrone Methoden verwenden und richtig warten, wenn Sie Entity Framework Core verwenden, um auf Azure Cosmos DB zuzugreifen. Weitere Informationen finden Sie unter https://aka.ms/ef-cosmos-nosync.

Warum?

Synchrone Blockierung für asynchrone Methoden kann zu Deadlock führen, und das Azure Cosmos DB SDK unterstützt nur asynchrone Methoden.

Gegenmaßnahmen

In EF Core 9.0 kann der Fehler unterdrückt werden mit:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.ConfigureWarnings(w => w.Ignore(CosmosEventId.SyncNotSupported));
}

In diesem Fall sollten Anwendungen die Verwendung von Synchronisierungs-APIs mit Azure Cosmos DB beenden, da dies vom Azure Cosmos DB SDK nicht unterstützt wird. Die Möglichkeit, die Ausnahme zu unterdrücken, wird in einer zukünftigen Version von EF Core entfernt, wonach die einzige Option die Verwendung asynchroner APIs sein wird.

SQL-Abfragen müssen jetzt JSON-Werte direkt projizieren

Verfolgung von Issue #25527

Altes Verhalten

Zuvor generierte EF Abfragen wie die folgenden:

SELECT c["City"] FROM root c

Solche Abfragen führen dazu, dass Azure Cosmos DB jedes Ergebnis in einem JSON-Objekt wie folgt umbrechen:

[
    {
        "City": "Berlin"
    },
    {
        "City": "México D.F."
    }
]
Neues Verhalten

Ab EF Core 9.0 fügt EF nun den VALUE Modifizierer zu Abfragen wie folgt hinzu:

SELECT VALUE c["City"] FROM root c

Solche Abfragen führen dazu, dass Azure Cosmos DB die Werte direkt zurückgeben, ohne umbrochen zu werden:

[
    "Berlin",
    "México D.F."
]

Wenn Ihre Anwendung SQL-Abfragen verwendet, werden solche Abfragen wahrscheinlich nach dem Upgrade auf EF 9.0 unterbrochen, da sie den VALUE Modifizierer nicht enthalten.

Warum?

Das Umschließen jedes Ergebnisses in ein zusätzliches JSON-Objekt kann in einigen Szenarien zu Leistungsbeeinträchtigungen führen, die JSON-Ergebnisnutzlast aufblähen und ist nicht die natürliche Möglichkeit, mit Azure Cosmos DB zu arbeiten.

Gegenmaßnahmen

Um dies zu vermeiden, fügen Sie einfach den VALUE Modifizierer zu den Projektionen Ihrer SQL-Abfragen hinzu, wie oben gezeigt.

Nicht definierte Ergebnisse werden jetzt automatisch aus Abfrageergebnissen gefiltert

Verfolgung von Issue #25527

Altes Verhalten

Zuvor generierte EF Abfragen wie die folgenden:

SELECT c["City"] FROM root c

Solche Abfragen führen dazu, dass Azure Cosmos DB jedes Ergebnis in einem JSON-Objekt wie folgt umbrechen:

[
    {
        "City": "Berlin"
    },
    {
        "City": "México D.F."
    }
]

Wenn eines der Ergebnisse nicht definiert war (z. B. die City Eigenschaft fehlte im Dokument), wurde ein leeres Dokument zurückgegeben, und EF würde null für dieses Ergebnis zurückgeben.

Neues Verhalten

Ab EF Core 9.0 fügt EF nun den VALUE Modifizierer zu Abfragen wie folgt hinzu:

SELECT VALUE c["City"] FROM root c

Solche Abfragen führen dazu, dass Azure Cosmos DB die Werte direkt zurückgeben, ohne umbrochen zu werden:

[
    "Berlin",
    "México D.F."
]

Das Azure Cosmos DB Verhalten besteht darin, undefined Werte automatisch aus den Ergebnissen herauszufiltern. Dies bedeutet, dass eine der City Eigenschaften nicht im Dokument vorhanden ist, würde die Abfrage nur ein einzelnes Ergebnis und nicht zwei Ergebnisse zurückgeben, wobei eines null ist.

Warum?

Das Umschließen jedes Ergebnisses in ein zusätzliches JSON-Objekt kann in einigen Szenarien zu Leistungsbeeinträchtigungen führen, die JSON-Ergebnisnutzlast aufblähen und ist nicht die natürliche Möglichkeit, mit Azure Cosmos DB zu arbeiten.

Gegenmaßnahmen

Wenn das Abrufen von null Werten für nicht definierte Ergebnisse für Ihre Anwendung wichtig ist, fassen Sie die undefined Werte zu null zusammen, indem Sie den neuen EF.Functions.Coalesce Operator verwenden.

var users = await context.Customer
    .Select(c => EF.Functions.CoalesceUndefined(c.City, null))
    .ToListAsync();

Falsch übersetzte Abfragen werden nicht mehr übersetzt

Verfolgung von Issue #34123

Altes Verhalten

Zuvor übersetzte EF Abfragen wie die folgende:

var sessions = await context.Sessions
    .Take(5)
    .Where(s => s.Name.StartsWith("f"))
    .ToListAsync();

Die SQL-Übersetzung für diese Abfrage war jedoch falsch:

SELECT c
FROM root c
WHERE ((c["Discriminator"] = "Session") AND STARTSWITH(c["Name"], "f"))
OFFSET 0 LIMIT @__p_0

In SQL wird die WHERE Klausel vor den OFFSET und LIMIT Klauseln ausgewertet. In der obigen LINQ-Abfrage wird der Take Operator jedoch vor dem Where Operator angezeigt. Daher könnten solche Abfragen falsche Ergebnisse zurückgeben.

Neues Verhalten

Ab EF Core 9.0 werden solche Abfragen nicht mehr übersetzt, und eine Ausnahme wird ausgelöst.

Warum?

Falsche Übersetzungen können zu einer stillen Datenbeschädigung führen, was zu schwierig zu entdeckenden Fehlern in Ihrer Anwendung führen kann. EF bevorzugt es immer, so früh wie möglich zu scheitern, indem sofort eine Ausnahme ausgelöst wird, anstatt möglicherweise zu Datenkorruption zu führen.

Gegenmaßnahmen

Wenn Sie mit dem vorherigen Verhalten zufrieden waren und dasselbe SQL ausführen möchten, tauschen Sie einfach die Reihenfolge der LINQ-Operatoren aus:

var sessions = await context.Sessions
    .Where(s => s.Name.StartsWith("f"))
    .Take(5)
    .ToListAsync();

Leider unterstützt Azure Cosmos DB derzeit nicht die OFFSET und LIMIT Klauseln in SQL-Unterabfragen, was die richtige Übersetzung der ursprünglichen LINQ-Abfrage erfordert.

Änderungen mit geringer Auswirkung

HasIndex wird jetzt ausgelöst, anstatt ignoriert zu werden

Nachverfolgungs-Issue #34023

Altes Verhalten

Zuvor wurden HasIndex-Aufrufe vom EF Cosmos DB-Anbieter ignoriert.

Neues Verhalten

Der Anbieter löst jetzt aus, wenn HasIndex angegeben wird.

Warum?

In Azure Cosmos DB sind standardmäßig alle Eigenschaften indiziert, sodass keine Indizierung angegeben werden muss. Obwohl es möglich ist, eine benutzerdefinierte Indizierungsrichtlinie zu definieren, wird dies derzeit nicht von EF unterstützt und kann über die Azure-Portal ohne EF-Unterstützung erfolgen. Da HasIndex Aufrufe nichts getan haben, sind sie nicht mehr zulässig.

Gegenmaßnahmen

Entferne alle Aufrufe von HasIndex.

IncludeRootDiscriminatorInJsonId wurde nach 9.0.0-rc.2 in HasRootDiscriminatorInJsonId umbenannt

Tracking-Issue #34717

Altes Verhalten

Die API IncludeRootDiscriminatorInJsonId wurde in 9.0.0 rc.1 eingeführt.

Neues Verhalten

Für die endgültige Version von EF Core 9.0 wurde die API umbenannt in HasRootDiscriminatorInJsonId

Warum?

Eine andere verwandte API wurde umbenannt, um mit Has statt Include zu beginnen, und daher wurde diese API auch für Konsistenz umbenannt.

Gegenmaßnahmen

Wenn Ihr Code die IncludeRootDiscriminatorInJsonId API verwendet, ändern Sie ihn einfach so, dass er stattdessen HasRootDiscriminatorInJsonId referenziert.

Die referenzierte Newtonsoft.Json-Version wurde von 10.0.2 auf 13.0.1 aktualisiert.

Altes Verhalten

Der Cosmos-Anbieter hat auf Newtonsoft.Json, Version 10.0.2 verwiesen.

Neues Verhalten

Ab EF Core 9.0 verweist der Cosmos-Anbieter auf Newtonsoft.Json, Version 13.0.1.

Warum?

Die zuvor referenzierte Version von Newtonsoft.Json hat bekannte Sicherheitsrisiken. Die Version wurde aktualisiert, um die Abhängigkeit von einer Paketversion mit bekannten Sicherheitsproblemen zu vermeiden.

Gegenmaßnahmen

Das Upgrade auf Newtonsoft.Json 13.0.1 sollte in den meisten Fällen keine Probleme verursachen. Wenn Ihre Anwendung Newtonsoft.Json direkt verwendet und auf eine bestimmte ältere Version angewiesen ist, können Sie Ihre Anwendung so aktualisieren, dass sie mit Newtonsoft.Json 13.0.1 oder höher kompatibel ist. Details zu Änderungen zwischen Versionen finden Sie in den Versionshinweisen zu Newtonsoft.Json .