Freigeben über


Grundlegende Änderungen in EF Core 10 (EF10)

Diese Seite dokumentiert API- und Verhaltensänderungen, die das Potenzial haben, vorhandene Anwendungen, die von EF Core 9 auf EF Core 10 aktualisiert werden, zu unterbrechen. Überprüfen Sie frühere grundlegende Änderungen, wenn sie von einer früheren Version von EF Core aktualisiert werden:

Zusammenfassung

Hinweis

Wenn Sie Microsoft.Data.Sqlite verwenden, lesen Sie den separaten Abschnitt unten über kompatibilitätsbrechende Änderungen von Microsoft.Data.Sqlite.

Wichtige Änderung Auswirkung
EF-Tools erfordern jetzt die Angabe eines Frameworks für mehrzielgerichtete Projekte. Mittelstufe
Der Anwendungsname wird jetzt in die Verbindungszeichenfolge eingefügt. Low
SQL Server-JSON-Datentyp, der standardmäßig in Azure SQL und Kompatibilitätsebene 170 verwendet wird Low
Parametrisierte Auflistungen verwenden jetzt standardmäßig mehrere Parameter. Low
ExecuteUpdateAsync akzeptiert jetzt ein reguläres Nicht-Ausdrucks-Lambda Low
Komplexe Spaltennamen des Typs sind jetzt eindeutig gemacht. Low
Geschachtelte komplexe Typeigenschaften verwenden den vollständigen Pfad in Spaltennamen. Low
IDiscriminatorPropertySetConvention-Signatur geändert Low
IRelationalCommandDiagnosticsLogger-Methoden fügen logCommandText-Parameter hinzu Low

Änderungen mit mittlerer Auswirkung

EF-Tools erfordern jetzt die Angabe von Frameworks für mehrorientierte Projekte.

Problemverfolgung Nr. 37230

Altes Verhalten

Bisher konnten die EF-Tools (dotnet-ef) für Projekte verwendet werden, die auf mehrere Frameworks abzielen, ohne anzugeben, welches Framework verwendet werden soll.

Neues Verhalten

Ab EF Core 10.0 müssen Sie beim Ausführen von EF-Tools für ein Projekt, das auf mehrere Frameworks ausgerichtet ist (anstelle <TargetFrameworks> von <TargetFramework>), explizit angeben, welches Zielframework mit der --framework Option verwendet werden soll. Ohne diese Option wird der folgende Fehler ausgelöst:

Das Projekt zielt auf mehrere Frameworks ab. Verwenden Sie die Option --framework, um anzugeben, welches Zielframework verwendet werden soll.

Warum

In EF Core 10 haben die Tools mit der Verwendung der ResolvePackageAssets MSBuild-Aufgabe begonnen, um genauere Informationen zu Projektabhängigkeiten zu erhalten. Dieser Vorgang ist jedoch nicht verfügbar, wenn das Projekt auf mehrere Zielframeworks (TFMs) ausgerichtet ist. Für die Lösung müssen Benutzer auswählen, welches Framework verwendet werden soll.

Gegenmaßnahmen

Wenn Sie einen EF-Tools-Befehl für ein Projekt ausführen, das auf mehrere Frameworks ausgerichtet ist, geben Sie das Zielframework mithilfe der --framework Option an. Beispiel:

dotnet ef migrations add MyMigration --framework net9.0
dotnet ef database update --framework net9.0
dotnet ef migrations script --framework net9.0

Wenn die Projektdatei wie folgt aussieht:

<PropertyGroup>
  <TargetFrameworks>net8.0;net9.0</TargetFrameworks>
</PropertyGroup>

Sie müssen eines der Frameworks (z. B. net9.0) auswählen, wenn Sie die EF-Tools ausführen.

Änderungen mit geringer Auswirkung

Der Anwendungsname wird jetzt in die Verbindungszeichenfolge eingefügt.

Nachverfolgung von Vorfällen Nr. 35730

Neues Verhalten

Wenn eine Verbindungszeichenfolge ohne Application Name an EF übergeben wird, fügt EF jetzt ein Application Name ein, das anonyme Informationen über die verwendeten Versionen von EF und SqlClient enthält. In den meisten Fällen wirkt sich dies auf keine Weise auf die Anwendung aus, kann sich aber in einigen Spezialfällen auf das Verhalten auswirken. Wenn Sie z. B. eine Verbindung mit derselben Datenbank mit EF und einer anderen Nicht-EF-Datenzugriffstechnologie (z. B. Dapper, ADO.NET) herstellen, verwendet SqlClient einen anderen internen Verbindungspool, da EF jetzt eine andere aktualisierte Verbindungszeichenfolge verwendet (eine, in die Application Name einjiziert wurde). Wenn diese Art von gemischtem Zugriff innerhalb eines TransactionScope durchgeführt wird, kann dies zu einer verteilten Transaktion führen, obwohl zuvor keine erforderlich war. Dies liegt an der Verwendung von zwei Verbindungs-Strings, die SqlClient als zwei unterschiedliche Datenbanken identifiziert.

Gegenmaßnahmen

Eine Entschärfung besteht darin, einfach eine Application Name in Ihrer Verbindungszeichenfolge zu definieren. Sobald eine definiert ist, überschreibt EF sie nicht, und die ursprüngliche Verbindungszeichenfolge wird genau "as-is" beibehalten.

SQL Server-JSON-Datentyp, der standardmäßig in Azure SQL und Kompatibilitätsebene 170 verwendet wird

Problemverfolgung Nr. 36372

Altes Verhalten

Früher speicherte der SQL Server-Anbieter beim Zuordnen von primitiven Auflistungen oder besitzereigenen Typen zu JSON in einer nvarchar(max) Spalte die JSON-Daten:

public class Blog
{
    // ...

    // Primitive collection, mapped to nvarchar(max) JSON column
    public string[] Tags { get; set; }
    // Owned entity type mapped to nvarchar(max) JSON column
    public List<Post> Posts { get; set; }
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>().OwnsMany(b => b.Posts, b => b.ToJson());
}

Für die vorstehende Tabelle hat EF zuvor die folgende Tabelle generiert:

CREATE TABLE [Blogs] (
    ...
    [Tags] nvarchar(max),
    [Posts] nvarchar(max)
);

Neues Verhalten

Wenn Sie EF UseAzureSql mit EF 10 konfigurieren (siehe Dokumentation) oder EF mit einer Kompatibilitätsstufe von 170 oder höher konfigurieren (siehe Dokumentation), wird EF stattdessen dem neuen JSON-Datentyp zugeordnet:

CREATE TABLE [Blogs] (
    ...
    [Tags] json
    [Posts] json
);

Obwohl der neue JSON-Datentyp die empfohlene Methode zum Speichern von JSON-Daten in SQL Server in Zukunft ist, gibt es möglicherweise einige Verhaltensunterschiede beim Übergang von nvarchar(max), und einige bestimmte Abfrageformulare werden möglicherweise nicht unterstützt. Beispielsweise unterstützt SQL Server den DISTINCT-Operator nicht über JSON-Arrays, und Abfragen, die versuchen, dies zu tun, schlagen fehl.

Beachten Sie, dass bei Verwendung einer vorhandenen Tabelle ein UseAzureSqlUpgrade auf EF 10 dazu führt, dass eine Migration generiert wird, die alle vorhandenen nvarchar(max) JSON-Spalten jsonändert. Dieser Änderungsvorgang wird unterstützt und sollte nahtlos und ohne Probleme angewendet werden, ist jedoch eine nicht triviale Änderung an Ihrer Datenbank.

Warum

Der neue VON SQL Server eingeführte JSON-Datentyp ist eine überlegene, 1. Klasse zum Speichern und Interagieren mit JSON-Daten in der Datenbank; sie bringt insbesondere erhebliche Leistungsverbesserungen mit sich (siehe Dokumentation). Alle Anwendungen, die Azure SQL-Datenbank oder SQL Server 2025 verwenden, werden empfohlen, zum neuen JSON-Datentyp zu migrieren.

Gegenmaßnahmen

Wenn Sie auf azure SQL-Datenbank abzielen und nicht sofort auf den neuen JSON-Datentyp umsteigen möchten, können Sie EF mit einer Kompatibilitätsstufe unter 170 konfigurieren:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseAzureSql("<connection string>", o => o.UseCompatibilityLevel(160));
}

Wenn Sie auf lokale SQL Server abzielen, beträgt die Standardkompatibilitätsstufe UseSqlServer derzeit 150 (SQL Server 2019), sodass der JSON-Datentyp nicht verwendet wird.

Alternativ können Sie den Spaltentyp explizit auf bestimmte Eigenschaften festlegen:nvarchar(max)

public class Blog
{
    public string[] Tags { get; set; }
    public List<Post> Posts { get; set; }
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>().PrimitiveCollection(b => b.Tags).HasColumnType("nvarchar(max)");
    modelBuilder.Entity<Blog>().OwnsMany(b => b.Posts, b => b.ToJson().HasColumnType("nvarchar(max)"));
    modelBuilder.Entity<Blog>().ComplexProperty(e => e.Posts, b => b.ToJson());
}

Parametrisierte Auflistungen verwenden jetzt standardmäßig mehrere Parameter.

Tracking-Issue Nr. 34346

Altes Verhalten

In EF Core 9 und früheren Versionen wurden parametrisierte Auflistungen in LINQ-Abfragen (z. B. die mit .Contains()) standardmäßig in SQL mit einem JSON-Arrayparameter übersetzt. Betrachten Sie die folgende Abfrage:

int[] ids = [1, 2, 3];
var blogs = await context.Blogs.Where(b => ids.Contains(b.Id)).ToListAsync();

Auf SQL Server hat dies die folgende SQL-Datei generiert:

@__ids_0='[1,2,3]'

SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
WHERE [b].[Id] IN (
    SELECT [i].[value]
    FROM OPENJSON(@__ids_0) WITH ([value] int '$') AS [i]
)

Neues Verhalten

Ab EF Core 10.0 werden parametrisierte Auflistungen standardmäßig mit mehreren skalaren Parametern übersetzt:

SELECT [b].[Id], [b].[Name]
FROM [Blogs] AS [b]
WHERE [b].[Id] IN (@ids1, @ids2, @ids3)

Warum

Die neue Standardübersetzung bietet dem Abfrageplaner Kardinalitätsinformationen zur Sammlung, was zu besseren Abfrageplänen in vielen Szenarien führen kann. Der Ansatz mit mehreren Parametern ermöglicht eine Balance zwischen der Effizienz des Plancaches (durch die Parameterisierung) und der Optimierung von Abfragen (durch die Berücksichtigung der Kardinalität).

Je nach Sammlungsgrößen, Abfragemustern und Datenbankmerkmalen können verschiedene Workloads von unterschiedlichen Übersetzungsstrategien profitieren.

Gegenmaßnahmen

Wenn Probleme mit dem neuen Standardverhalten auftreten (z. B. Leistungsregressionen), können Sie den Übersetzungsmodus global konfigurieren:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .UseSqlServer("<CONNECTION STRING>", 
            o => o.UseParameterizedCollectionMode(ParameterTranslationMode.Constant));

Verfügbare Modi sind:

  • ParameterTranslationMode.MultipleParameters - Der neue Standardwert (mehrere skalare Parameter)
  • ParameterTranslationMode.Constant - Inline-Werte als Konstanten (Standardverhalten vor EF8)
  • ParameterTranslationMode.Parameter - Verwendet JSON-Arrayparameter (EF8-9-Standard)

Sie können die Übersetzung auch pro Abfrage steuern:

// Use constants instead of parameters for this specific query
var blogs = await context.Blogs
    .Where(b => EF.Constant(ids).Contains(b.Id))
    .ToListAsync();

// Use a single parameter (e.g. JSON parameter with OPENJSON) instead of parameters for this specific query
var blogs = await context.Blogs
    .Where(b => EF.Parameter(ids).Contains(b.Id))
    .ToListAsync();

// Use multiple scalar parameters for this specific query. This is the default in EF 10, but is useful if the default was changed globally:
var blogs = await context.Blogs
    .Where(b => EF.MultipleParameters(ids).Contains(b.Id))
    .ToListAsync();

Weitere Informationen zur parametrisierten Sammlungsübersetzung finden Sie in der Dokumentation.

ExecuteUpdateAsync akzeptiert jetzt eine normale Lambda-Funktion ohne Ausdruck

Nachverfolgung von Issue 32018

Altes Verhalten

Zuvor akzeptierte ExecuteUpdate ein Ausdrucksbaum-Argument (Expression<Func<...>>) für die Spalten-Setter.

Neues Verhalten

Ab EF Core 10.0 akzeptiert ExecuteUpdate nun ein Nichtausdrucksargument (Func<...>) für die Spaltensatzer. Wenn Sie Ausdrucksbäume erstellt haben, um das Argument "Spalten-Setter" dynamisch zu erstellen, wird Ihr Code nicht mehr kompiliert, lässt sich jedoch durch eine viel einfachere Alternative ersetzen (siehe unten).

Warum

Die Tatsache, dass der Parameter "Spaltensetzer" ein Ausdrucksbaum war, machte es ziemlich schwierig, die Spaltensetzer dynamisch zu konstruieren, wobei einige Setzer nur basierend auf bestimmten Bedingungen vorhanden sind (siehe unten stehende Maßnahmen für ein Beispiel).

Gegenmaßnahmen

Code, der Ausdrucksbäume erstellt hat, um das Spalteneinstellungsargument dynamisch zu erzeugen, muss neu geschrieben werden – aber das Ergebnis wird viel einfacher sein. Angenommen, Sie möchten die Ansichten eines Blogs aktualisieren, aber bedingt auch dessen Namen. Da das Setter-Argument ein Ausdrucksbaum war, musste folgender Code geschrieben werden:

// Base setters - update the Views only
Expression<Func<SetPropertyCalls<Blog>, SetPropertyCalls<Blog>>> setters =
    s => s.SetProperty(b => b.Views, 8);

// Conditionally add SetProperty(b => b.Name, "foo") to setters, based on the value of nameChanged
if (nameChanged)
{
    var blogParameter = Expression.Parameter(typeof(Blog), "b");

    setters = Expression.Lambda<Func<SetPropertyCalls<Blog>, SetPropertyCalls<Blog>>>(
        Expression.Call(
            instance: setters.Body,
            methodName: nameof(SetPropertyCalls<Blog>.SetProperty),
            typeArguments: [typeof(string)],
            arguments:
            [
                Expression.Lambda<Func<Blog, string>>(Expression.Property(blogParameter, nameof(Blog.Name)), blogParameter),
                Expression.Constant("foo")
            ]),
        setters.Parameters);
}

await context.Blogs.ExecuteUpdateAsync(setters);

Das manuelle Erstellen von Ausdrucksstrukturen ist kompliziert und fehleranfällig, wodurch dieses häufige Szenario deutlich schwieriger gemacht wurde, als es eigentlich sein sollte. Ab EF 10 können Sie stattdessen Folgendes schreiben:

await context.Blogs.ExecuteUpdateAsync(s =>
{
    s.SetProperty(b => b.Views, 8);
    if (nameChanged)
    {
        s.SetProperty(b => b.Name, "foo");
    }
});

Spaltennamen komplexer Typen sind jetzt eindeutig gemacht.

Verfolgungsnummer Nr. 4970

Altes Verhalten

Zuvor, wenn komplexe Typen Tabellenspalten zugeordnet wurden, konnten mehrere Eigenschaften in verschiedenen komplexen Typen denselben Spaltennamen aufweisen und so stillschweigend dieselbe Spalte gemeinsam nutzen.

Neues Verhalten

Beginnend mit EF Core 10.0 werden Spaltennamen für komplexe Typen eindeutig gemacht, indem eine Zahl an das Ende angefügt wird, wenn eine andere Spalte mit demselben Namen in der Tabelle vorhanden ist.

Warum

Dadurch werden Datenbeschädigungen verhindert, die auftreten können, wenn mehrere Eigenschaften unbeabsichtigt derselben Spalte zugeordnet sind.

Gegenmaßnahmen

Wenn Sie mehrere Eigenschaften für die gemeinsame Nutzung derselben Spalte benötigen, konfigurieren Sie sie explizit mithilfe Property und HasColumnName:

modelBuilder.Entity<Customer>(b =>
{
    b.ComplexProperty(c => c.ShippingAddress, p => p.Property(a => a.Street).HasColumnName("Street"));
    b.ComplexProperty(c => c.BillingAddress, p => p.Property(a => a.Street).HasColumnName("Street"));
});

Geschachtelte komplexe Typeigenschaften verwenden den vollständigen Pfad in Spaltennamen.

Altes Verhalten

Zuvor wurden Eigenschaften für geschachtelte komplexe Typen mit nur dem deklarierenden Typnamen auf Spalten abgebildet. Beispielsweise EntityType.Complex.NestedComplex.Property wurde der Spalte NestedComplex_Propertyzugeordnet.

Neues Verhalten

Ab EF Core 10.0 verwenden Eigenschaften für geschachtelte komplexe Typen den vollständigen Pfad zur Eigenschaft als Teil des Spaltennamens. Beispiel: EntityType.Complex.NestedComplex.Property ist jetzt Spalte Complex_NestedComplex_Propertyzugeordnet.

Warum

Dies bietet eine bessere Eindeutigkeit von Spaltennamen und macht deutlicher, welche Eigenschaft welcher Spalte zugeordnet ist.

Gegenmaßnahmen

Wenn Sie die alten Spaltennamen beibehalten müssen, konfigurieren Sie sie explizit mit Property und HasColumnName:

modelBuilder.Entity<EntityType>()
    .ComplexProperty(e => e.Complex)
    .ComplexProperty(o => o.NestedComplex)
    .Property(c => c.Property)
    .HasColumnName("NestedComplex_Property");

Die Signatur von IDiscriminatorPropertySetConvention wurde geändert.

Altes Verhalten

Zuvor nahm IDiscriminatorPropertySetConvention.ProcessDiscriminatorPropertySetIConventionEntityTypeBuilder als Parameter.

Neues Verhalten

Ab EF Core 10.0 wurde die Methodensignatur geändert, sodass sie IConventionTypeBaseBuilder anstelle von IConventionEntityTypeBuilder verwendet.

Warum

Diese Änderung ermöglicht es der Konvention, sowohl mit Entitätstypen als auch mit komplexen Typen zu arbeiten.

Gegenmaßnahmen

Aktualisieren Sie Ihre Implementierungen von benutzerdefinierten Konventionen, um die neue Signatur zu verwenden.

public virtual void ProcessDiscriminatorPropertySet(
    IConventionTypeBaseBuilder typeBaseBuilder, // Changed from IConventionEntityTypeBuilder
    string name,
    Type type,
    MemberInfo memberInfo,
    IConventionContext<IConventionProperty> context)

IRelationalCommandDiagnosticsLogger-Methoden fügen logCommandText-Parameter hinzu

Problemverfolgung Nr. 35757

Altes Verhalten

Zuvor haben Methoden IRelationalCommandDiagnosticsLogger wie CommandReaderExecuting, CommandReaderExecuted, CommandScalarExecuting, und andere einen command Parameter akzeptiert, der den Datenbankbefehl darstellt, der ausgeführt wird.

Neues Verhalten

Ab EF Core 10.0 benötigen diese Methoden jetzt einen zusätzlichen logCommandText Parameter. Dieser Parameter enthält den SQL-Befehlstext, der protokolliert wird und bei dem möglicherweise vertrauliche Daten geschwärzt werden, wenn EnableSensitiveDataLogging nicht aktiviert ist.

Warum

Diese Änderung unterstützt das neue Feature, um eingebettete Konstanten standardmäßig aus der Protokollierung zu verbergen. Wenn Entity Framework Parameterwerte in SQL (z. B. bei Verwendung von EF.Constant()) einfügt, werden diese Werte jetzt in den Protokollen maskiert, es sei denn, die Protokollierung vertraulicher Daten ist explizit aktiviert. Der logCommandText Parameter stellt die redacted SQL für Protokollierungszwecke bereit, während der command Parameter den tatsächlichen SQL-Wert enthält, der ausgeführt wird.

Gegenmaßnahmen

Wenn Sie über eine benutzerdefinierte Implementierung IRelationalCommandDiagnosticsLogger verfügen, müssen Sie die Methodensignaturen aktualisieren, um den neuen Parameter logCommandText einzuschließen. Beispiel:

public InterceptionResult<DbDataReader> CommandReaderExecuting(
    IRelationalConnection connection,
    DbCommand command,
    DbContext context,
    Guid commandId,
    Guid connectionId,
    DateTimeOffset startTime,
    string logCommandText) // New parameter
{
    // Use logCommandText for logging purposes
    // Use command for execution-related logic
}

Der logCommandText Parameter enthält die SQL-Datei, die protokolliert werden soll (mit inlineierten Konstanten, die potenziell redigiert sind), und command.CommandText enthält den tatsächlichen SQL-Wert, der für die Datenbank ausgeführt wird.

Microsoft.Data.Sqlite – Wichtige Änderungen

Zusammenfassung

Wichtige Änderung Auswirkung
Die Verwendung von GetDateTimeOffset ohne Offset geht jetzt standardmäßig von UTC aus High
Das Schreiben eines DateTimeOffset in eine REAL-Spalte erfolgt jetzt in UTC High
Die Verwendung von GetDateTime mit einem Offset gibt jetzt den Wert in UTC zurück. High

Änderungen mit hoher Auswirkung

Beim Verwenden von GetDateTimeOffset ohne einen Offset wird jetzt davon ausgegangen, dass UTC verwendet wird.

Nachverfolgung von Issue 36195

Altes Verhalten

Wenn GetDateTimeOffset auf einen Textzeitstempel angewendet wird, der keinen Offset (z. B. 2014-04-15 10:47:16) aufweist, nimmt Microsoft.Data.Sqlite an, dass der Wert in der lokalen Zeitzone liegt. D.h. der Wert wurde analysiert als 2014-04-15 10:47:16+02:00 (vorausgesetzt, die lokale Zeitzone war UTC+2).

Neues Verhalten

Ab Microsoft.Data.Sqlite 10.0 wird bei Verwendung GetDateTimeOffset eines textbezogenen Zeitstempels, der keinen Offset aufweist, von Microsoft.Data.Sqlite vorausgesetzt, dass der Wert in UTC liegt.

Warum

Entspricht dem Verhalten von SQLite, bei dem Zeitstempel ohne Offset als UTC behandelt werden.

Gegenmaßnahmen

Der Code sollte entsprechend angepasst werden.

Als letztes/temporäres Mittel können Sie zum vorherigen Verhalten zurückkehren, indem Sie den AppContext-Schalter auf Microsoft.Data.Sqlite.Pre10TimeZoneHandling"AppContext" festlegentrue. Weitere Informationen finden Sie unter AppContext für Bibliothekskunden.

AppContext.SetSwitch("Microsoft.Data.Sqlite.Pre10TimeZoneHandling", isEnabled: true);

Schreiben von DateTimeOffset in REAL-Spalte wird jetzt in UTC geschrieben

Nachverfolgung von Issue 36195

Altes Verhalten

Früher, beim Schreiben eines DateTimeOffset Werts in eine REAL-Spalte, schrieb Microsoft.Data.Sqlite den Wert, ohne den Offset zu berücksichtigen.

Neues Verhalten

Ab Microsoft.Data.Sqlite 10.0 konvertiert Microsoft.Data.Sqlite beim Schreiben eines DateTimeOffset Werts in eine REAL-Spalte den Wert in UTC, bevor die Konvertierungen ausgeführt und geschrieben werden.

Warum

Der geschriebene Wert war falsch und entsprach nicht dem Verhalten von SQLite, bei dem davon ausgegangen wird, dass REAL-Zeitstempel UTC sind.

Gegenmaßnahmen

Der Code sollte entsprechend angepasst werden.

Als letztes/temporäres Mittel können Sie zum vorherigen Verhalten zurückkehren, indem Sie den AppContext-Schalter auf Microsoft.Data.Sqlite.Pre10TimeZoneHandling"AppContext" festlegentrue. Weitere Informationen finden Sie unter AppContext für Bibliothekskunden.

AppContext.SetSwitch("Microsoft.Data.Sqlite.Pre10TimeZoneHandling", isEnabled: true);

Die Verwendung von GetDateTime mit einem Offset gibt jetzt den Wert in UTC zurück.

Nachverfolgung von Issue 36195

Altes Verhalten

Früher, wenn GetDateTime auf einen Textzeitstempel mit einem Offset (z. B. 2014-04-15 10:47:16+02:00) angewendet wurde, gab Microsoft.Data.Sqlite den Wert mit DateTimeKind.Local zurück, selbst wenn der Offset nicht lokal war. Die Zeit wurde unter Berücksichtigung des Offsets richtig analysiert.

Neues Verhalten

Ab Microsoft.Data.Sqlite 10.0 wird bei der Verwendung von GetDateTime auf einen Textzeitstempel mit einem Offset Microsoft.Data.Sqlite den Wert in UTC konvertieren und ihn mit DateTimeKind.Utc zurückgeben.

Warum

Obwohl die Zeit richtig analysiert wurde, hängt sie von der vom Computer konfigurierten lokalen Zeitzone ab, was zu unerwarteten Ergebnissen führen könnte.

Gegenmaßnahmen

Der Code sollte entsprechend angepasst werden.

Als letztes/temporäres Mittel können Sie zum vorherigen Verhalten zurückkehren, indem Sie den AppContext-Schalter auf Microsoft.Data.Sqlite.Pre10TimeZoneHandling"AppContext" festlegentrue. Weitere Informationen finden Sie unter AppContext für Bibliothekskunden.

AppContext.SetSwitch("Microsoft.Data.Sqlite.Pre10TimeZoneHandling", isEnabled: true);