Schreiben eines Datenbankanbieters

Informationen zum Schreiben eines Entity Framework Core-Datenbankanbieters finden Sie unter Sie möchten also einen EF Core-Anbieter schreiben von Arthur Vickers.

Hinweis

Diese Beiträge wurden seit EF Core 1.1 nicht aktualisiert, und es gab seit dieser Zeit erhebliche Änderungen. Problem 681 verfolgt Updates dieser Dokumentation nach.

Die EF Core-Codebasis ist Open Source und enthält mehrere Datenbankanbieter, die als Referenz verwendet werden können. Den Quellcode finden Sie unter https://github.com/dotnet/efcore. Es kann auch hilfreich sein, den Code für häufig verwendete Drittanbieter wie Npgsql, Pomelo MySQL und SQL Server Compact zu betrachten. Diese Projekte werden insbesondere eingerichtet, um von funktionsbezogenen Tests auszugehen, die wir auf NuGet veröffentlichen, und sie auszuführen. Diese Art von Setup wird dringend empfohlen.

Bei Anbieteränderungen auf dem Laufenden bleiben

Nach Version 2.1 mit der Arbeit beginnend haben wir ein Protokoll von Änderungen erstellt, die möglicherweise entsprechende Änderungen im Anbietercode erfordern. Dies soll beim Aktualisieren eines vorhandenen Anbieters helfen, um mit einer neuen Version von EF Core zu arbeiten.

Vor Version 2.1 haben wir die Bezeichnungen providers-beware und providers-fyi für unsere GitHub-Probleme und Pull Requests für einen ähnlichen Zweck verwendet. Wir werden diese Bezeichnungen weiterhin für Probleme verwenden, um darauf hinzuweisen, welche Arbeitselemente in einer bestimmten Version möglicherweise auch Arbeit bei Anbietern erfordern. Eine providers-beware-Bezeichnung bedeutet in der Regel, dass die Implementierung eines Arbeitselements Anbieter beschädigen kann, während eine providers-fyi-Bezeichnung normalerweise bedeutet, dass Anbieter nicht beschädigt werden, aber möglicherweise trotzdem Code geändert werden muss, um beispielsweise neue Funktionen zu aktivieren.

Vorgeschlagene Benennung von Drittanbietern

Die folgende Benennung sollte für NuGet-Pakete verwendet werden. Dies entspricht den Namen der Pakete, die vom EF Core-Team geliefert werden.

<Optional project/company name>.EntityFrameworkCore.<Database engine name>

Beispiel:

  • Microsoft.EntityFrameworkCore.SqlServer
  • Npgsql.EntityFrameworkCore.PostgreSQL
  • EntityFrameworkCore.SqlServerCompact40

Die EF Core-Spezifikationstests

EF Core stellt ein Spezifikationstestsammlungs-Projekt bereit, das alle Anbieter implementieren sollten. Das Projekt enthält Tests, die sicherstellen, dass der Anbieter ordnungsgemäß funktioniert, z. B. durch Ausführen verschiedener LINQ-Abfragen und Sicherstellung, dass die richtigen Ergebnisse zurückgegeben werden. Diese Testsammlung wird von den eigenen Anbietern von EF Core (z. B. SQL Server, SQLite und Azure Cosmos DB) als primärer Regressionstestmechanismus verwendet und kontinuierlich aktualisiert und verbessert, wenn EF neue Features Core hinzugefügt werden. Durch die Implementierung dieser Tests für andere Drittanbieter können Sie sicherstellen, dass Ihr Datenbankanbieter ordnungsgemäß funktioniert und alle neuesten EF Core-Features implementiert. Beachten Sie, dass die Testsammlung ziemlich groß ist, da sie den gesamten EF Core-Featuresatz abdeckt. Sie müssen nicht alles implementieren – es reicht, wenn Sie bestimmte Testklassen auswählen und Ihre Abdeckung mit der Zeit inkrementell verbessern.

Führen Sie die folgenden Schritte aus, um mit der Verwendung der Spezifikationstests zu beginnen:

  • Erstellen Sie ein xUnit-Testprojekt in Ihrer Anbieterlösung. Wir schlagen den Namen <Provider>.FunctionalTests der Konsistenz wegen vor. Wenn Ihr Anbieter also AcmeSoftware.EntityFramework.AcmeDb heißt, rufen Sie das Testprojekt AcmeSoftware.EntityFramework.AcmeDb.FunctionalTests auf.
  • Verweisen Sie in Ihrem neuen Testprojekt auf die EF-Spezifikationstests, die als normale NuGet-Pakete veröffentlicht werden. Für relationale Anbieter ist die Spezifikationstestsammlung Microsoft.EntityFrameworkCore.Relational.Specification.Tests bestimmt, verwenden Sie für nicht relationale Anbieter Microsoft.EntityFrameworkCore.Specification.Tests).
  • Wählen Sie eine Testklasse aus den EF-Spezifikationstests aus, und erweitern Sie sie von einer entsprechenden Testklasse in Ihrem eigenen Projekt aus. Die verfügbaren Testklassen sind im EF-Quellcode zu sehen. Ihre Klasse sollte auf der EF-Testklasse basierend benannt werden, wobei Ihr Anbietername gegebenenfalls eingefügt wird. Beispielsweise würde NorthwindWhereQueryRelationalTestBase (was ein guter Ausgangspunkt ist) um NorthwindWhereQueryAcmeDbTest erweitert werden.
  • Zu Beginn müssen Sie eine gewisse Testinfrastruktur implementieren – danach werden die Dinge einfacher. Sie müssen z. B. NorthwindWhereQueryAcmeDbFixture für NorthwindWhereQueryAcmeDbTest implementieren, wofür eine AcmeDbNorthwindTestStoreFactory erforderlich ist, die ein Skript „Northwind.sql“ benötigen würde, um die AcmeDb-Version der Northwind-Datenbank zu starten. Es wird dringend empfohlen, die Testsammlung eines anderen EF Core-Anbieters in der Nähe zu nutzen und dem zu folgen, was sie tut. Die SQL Server-Implementierung der Spezifikationstests ist beispielsweise hier sichtbar.
  • Sobald die Infrastruktur für die Testklasse abgeschlossen ist, sehen Sie dort einige grüne Tests. Sie können die fehlerhaften Tests untersuchen oder sie vorübergehend für eine spätere Untersuchung überspringen. Auf diese Weise können Sie immer mehr Testklassen hinzufügen.
  • Wenn Sie die meisten Upstreamtestklassen erweitert haben, können Sie irgendwann auch AcmeDbComplianceTest erstellen, wodurch RelationalComplianceTestBase erweitert wird. Bei dieser Testklasse tritt ein Fehler auf, wenn Ihr eigenes Testprojekt keine EF Core-Testklasse erweitert. Dies ist eine hervorragende Möglichkeit, festzustellen, ob Ihre Testsammlung abgeschlossen ist, und auch, ob EF eine neue Testklasse in einer neuen Version hinzugefügt hat. Sie können auch die Erweiterung bestimmter Testklassen deaktivieren, wenn sie nicht bereit (oder nicht relevant) sind.

SQL-Assertions

Bei der Implementierung der Spezifikationstests haben Sie die Möglichkeit, zusätzlich den SQL-Code zu bestätigen, den EF Core erzeugt. Dies ist nicht zwingend erforderlich: Die Implementierung des Spezifikationstests überprüft bereits, ob ihr Anbieter die erwarteten Zeilen aus der Datenbank zurückgegeben hat. Wenn dies erfolgreich ist, tut Ihr Anbieter wahrscheinlich das richtige. Wenn Sie jedoch bestätigen, dass der SQL-Code Ihren Erwartungen entspricht, kann dies in einigen Fällen zusätzliche Sicherheit bieten, insbesondere, wenn einige SQL-Konstrukte verwendet werden, die für Ihre Datenbank spezifisch sind.

Hier ist beispielsweise der Where_simple-Test in der NorthwindWhereQuerySqlServerTest-Testklasse:

public override async Task Where_simple(bool async)
{
    await base.Where_simple(async);

    AssertSql(
        @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
WHERE [c].[City] = N'London'");
}

Der Basisaufruf führt den Spezifikationstest aus, der die LINQ-Abfrage ausführt und überprüft, ob die Ergebnisse korrekt sind. Darüber hinaus stellt AssertSql sicher, dass der SQL-Code mit dem im Test enthaltenen Basisplan übereinstimmt.

Überprüfen von SQL-Assertionfehlern

Wenn bei einer SQL-Assertion ein Fehler auftritt, meldet xunit in der Regel nur das Fragment des SQL-Codes, das nicht übereinstimmt. Um den vollständigen SQL-Code anzuzeigen, der vom Anbieter erstellt wird, können Sie die Testinfrastruktur den vollständigen neuen Basisplan ausgeben lassen, wenn bei einem Test ein Fehler auftritt, damit Sie ihn prüfen und möglicherweise den alten ersetzen können. Übergeben Sie dazu den von xunit bereitgestellten ITestOutputHelper an die TestSqlLoggerFactory der Testfixture:

public NorthwindWhereQuerySqlServerTest(
    NorthwindQuerySqlServerFixture<NoopModelCustomizer> fixture,
    ITestOutputHelper testOutputHelper)
    : base(fixture)
{
    ClearLog();
    Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper);
}

In den EF Core-Testsammlungen kommentieren wir in der Regel die oben genannte Zeile im Konstruktor aus, sodass wir die Kommentierung jederzeit aufheben können, wenn bei einer SQL-Assertion ein Fehler auftritt.

Massenaktualisierung von Basislinien

Wenn Sie häufig SQL-Assertions verwenden, enthält Ihre Testsammlung viele SQL-Basislinien. In einigen Fällen kann eine kleine Änderung – entweder in Ihrem Anbieter oder in EF Core selbst – dazu führen, dass bei einer großen Anzahl dieser Assertions aus beliebigem Grund ein Fehler auftritt, z. B. weil irgendwo Klammern hinzugefügt wurden. In diesem Fall kann die manuelle Korrektur aller betroffenen Basislinien ein sehr mühsamer und zeitaufwändiger Prozess sein.

Die EF Core-Testinfrastruktur verfügt über ein Feature, das alle fehlerhaften Basislinien automatisch mit den neuen aktualisiert. Legen Sie einfach die EF_TEST_REWRITE_BASELINES-Umgebungsvariable auf 1 fest, und führen Sie die Tests aus, und die Testquelldateien sollten aktualisiert werden. Zuvor sollte unbedingt ein Commit ausgeführt werden, und prüfen Sie dann mit Git die Testdifferenz, um sicherzustellen, dass die neuen Basislinien sinnvoll sind. Sobald Sie zufrieden sind, können Sie diese Änderungen auch committen.