编写数据库提供程序
关于如何编写 Entity Framework Core 数据库提供程序的信息,请参阅由 Arthur Vickers 编写的你想编写一个 EF Core 提供程序。
备注
这些帖子自 EF Core 1.1 以来就没有更新过,自那时起就发生了重大变化。 问题 681 正在跟踪对此文档的更新。
EF Core 代码库是开源的,包含多个可用作参考的数据库提供程序。 可以在 https://github.com/dotnet/efcore 上找到源代码。 查看常用的第三方提供程序(例如 Npgsql、Pomelo MySQL 和 SQL Server Compact)的代码也可能会有所帮助。 特别是,这些项目的设置是为了扩展和运行在 NuGet 上发布的功能测试。 强烈建议使用此设置。
从 2.1 版本开始,我们创建了一个更改日志,它可能需要对提供程序代码进行相应的更改。 这旨在更新现有提供程序以使用新版本的 EF Core 时提供帮助。
在 2.1 及更低版本中,我们针对 GitHub 问题和拉取请求使用了 providers-beware
和 providers-fyi
标签,以实现类似的目的。 我们将继续针对问题使用这些标签,以表明给定版本中的哪些工作项也可能需要在提供程序中完成工作。 providers-beware
标签通常表示工作项的实现可能会中断提供程序,而 providers-fyi
标签通常表示不会中断提供程序,但可能仍需更改代码,例如启用新功能。
我们建议对 NuGet 包使用以下命名。 这与 EF Core 团队交付的包名称一致。
<Optional project/company name>.EntityFrameworkCore.<Database engine name>
例如:
Microsoft.EntityFrameworkCore.SqlServer
Npgsql.EntityFrameworkCore.PostgreSQL
EntityFrameworkCore.SqlServerCompact40
EF Core 提供规范测试套件项目,鼓励所有提供程序实现该项目。 该项目包含可确保提供程序正常运行的测试,例如执行各种 LINQ 查询并确保返回正确的结果。 EF Core 自己的提供程序(如 SQL Server、SQLite 和 Azure Cosmos DB)使用此测试套件作为主要回归测试机制,随着新功能添加到 EF Core,该套件会不断更新和改进。 通过为其他第三方提供程序实现这些测试,你可以确保你的数据库提供程序正常工作并实现所有最新的 EF Core 功能。 请注意,测试套件相当大,因为它涵盖整个 EF Core 功能集。你不必实现所有内容,完全可以挑拣某些测试类,并随时间增量地提升你的覆盖范围。
要开始使用规范测试,请执行以下步骤:
- 在提供程序解决方案中创建 xUnit 测试项目。 我们建议使用名称
<Provider>.FunctionalTests
以保持一致性,因此,如果你的提供程序被调用了AcmeSoftware.EntityFramework.AcmeDb
,请调用测试项目AcmeSoftware.EntityFramework.AcmeDb.FunctionalTests
。 - 从新的测试项目中,引用作为常规 Nuget 包发布的 EF 规范测试。 对于关系提供程序,规范测试套件是 Microsoft.EntityFrameworkCore.Relational.Specification.Tests,对于非关系提供程序,请使用 Microsoft.EntityFrameworkCore.Specification.Tests。
- 从 EF 规范测试中选取一个测试类,并从你自己的项目中的相应测试类进行扩展。 可以在 EF 源代码中看到可用的测试类。 应根据 EF 测试类命名你的类,并在适当的情况下插入你的提供程序名称。 例如,
NorthwindWhereQueryRelationalTestBase
(一个很好的开头)将由NorthwindWhereQueryAcmeDbTest
扩展。 - 一开始,你会有一些测试基础结构要实现,一旦完成一次,事情就会变得简单起来。 例如,对于
NorthwindWhereQueryAcmeDbTest
,你必须实现NorthwindWhereQueryAcmeDbFixture
,而它需要AcmeDbNorthwindTestStoreFactory
,它需要 Northwind.sql 脚本来种子设定 Northwind 数据库的 AcmeDb 版本。 我们强烈建议在附近打开另一个 EF Core 提供程序的测试套件,并遵循它的作用。 例如,此处显示了规范测试的 SQL Server 实现。 - 测试类的基础结构完成后,你将开始看到一些绿色测试。 可以调查失败的测试,或暂时跳过这些测试,以后再调查。 这样,你可以添加越来越多的测试类。
- 到了某个时候,当你扩展了大部分上游测试类时,还可以创建
AcmeDbComplianceTest
,它会扩展RelationalComplianceTestBase
类。 如果你自己的测试项目不扩展 EF Core 测试类,则此测试类将失败–这是了解你的测试套件是否已完成,以及 EF 是否在新版本中添加了新的测试类的一个好方法。 如果特定测试类未准备就绪(或不相关),还可以选择退出扩展特定测试类。
实现规范测试时,可以选择另外断言 EF Core 生成的 SQL。 这不是强制性的:规范测试实现已经检查了你的提供程序是否从数据库返回了预期的行,因此如果通过,你的提供程序可能已经在执行正确的操作。 但是,通过断言 SQL 是你对它的期望,在某些情况下可能会增加额外的覆盖范围,尤其是某些特定于你的数据库的 SQL 构造正被使用时。
例如,下面是 NorthwindWhereQuerySqlServerTest 测试类中的 Where_simple
测试:
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'");
}
基本调用会运行规范测试,它会执行 LINQ 查询并验证结果是否正确。 此外,AssertSql
会确保 SQL 与测试中包含的基线匹配。
如果 SQL 断言失败,xunit 通常只报告不匹配的 SQL 片段。 要查看提供程序生成的完整 SQL,可以在测试失败时让测试基础结构输出完整的新基线,以便你可以检查它,甚至替换旧的基线。 为此,请将 xunit 提供的 ITestOutputHelper
传递给测试固定例程的 TestSqlLoggerFactory
:
public NorthwindWhereQuerySqlServerTest(
NorthwindQuerySqlServerFixture<NoopModelCustomizer> fixture,
ITestOutputHelper testOutputHelper)
: base(fixture)
{
ClearLog();
Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper);
}
在 EF Core 测试套件中,我们通常会在构造函数中注释禁止上述行,以便在 SQL 断言失败时方便地取消注释它。
如果你经常使用 SQL 断言,那么你的测试套件中会有许多 SQL 基线。 在某些情况下,你的提供程序或 EF Core 本身中的一些小更改可能会导致大量断言失败,原因可能是在某个位置添加了括号。 如果发生这种情况,手动更正所有受影响的基线可能是一个非常繁琐且耗时的过程。
EF Core 测试基础结构具有一项功能,它会用新基线自动更新所有失败的基线。 只需将 EF_TEST_REWRITE_BASELINES
环境变量设置为 1
并运行测试,测试源文件应该就会更新了。 建议在执行此操作之前进行提交,然后使用 git 检查测试差异,以确保新的基线有意义。 满足要求后,也可以提交那些更改。