使用 .NET.NET Aspire 向数据库中写入种子数据

本文介绍如何在应用启动时配置 .NET.NET Aspire 项目以在数据库中设定数据种子。 .NET Aspire 使你能够使用数据库脚本或 Entity Framework Core () 为常见平台(EF Core例如 SQL Server, PostgreSQL和 MySQL)设定数据种子。

何时进行数据种子初始化

初始化数据会预先填充数据库表的数据行,以便它们为应用测试做好准备。 你可能希望为以下场景设定数据种子:

  • 你想要针对一组有意义的数据(例如产品目录或客户列表)手动开发和测试应用的不同功能。
  • 你希望运行测试套件,以验证功能是否与给定数据集的行为正确。

手动输入数据非常繁琐且耗时,因此应尽可能自动化这个过程。 可以通过在启动期间为.NET Aspire项目运行数据库脚本,或使用像EF Core这样的工具(这些工具会处理许多基础问题),来初始化数据库。

了解容器化数据库

默认情况下,.NET.NET Aspire 数据库集成依赖于容器化数据库,这会在尝试设定数据种子时产生以下挑战:

  • 默认情况下,.NET.NET Aspire 每次应用重启时都会销毁并重新创建容器,这意味着您必须在每次运行时重新初始化数据库。
  • 根据所选的数据库技术,新的容器实例可能或可能不会创建默认数据库,这意味着可能还需要创建数据库本身。
  • 即使存在默认数据库,它很可能没有特定应用所需的名称或架构。

.NET.NET Aspire 使你能够使用卷、绑定装载和一些配置来有效地初始化数据,从而解决这些难题。

小窍门

容器主机(如 Docker 和 Podman)支持卷和绑定装载,这两者都为容器重启时保留的数据提供位置。 卷是推荐的解决方案,因为它们提供更好的性能、可移植性和安全性。 容器主机创建卷并保持对其的控制。 每个卷可以存储多个容器的数据。 相比之下,绑定装载的功能相对有限,但允许你从主机访问数据。

注意

访问 数据库容器示例应用 以查看每个数据库选项的完整项目和文件结构。

使用 SQL 脚本播种数据

用于执行数据库种子设定脚本的建议方法取决于所使用的数据库服务器:

从 .NET.NET Aspire 9.2 开始,可以使用 WithCreationScript 该方法来确保在创建数据库时运行 T-SQL 脚本。 将此脚本添加 SQL 代码,用于创建和填充数据库、必要的表和其他数据库对象。

以下代码是一个示例 T-SQL 脚本,用于创建和填充通讯簿数据库:

-- SQL Server init script

-- Create the AddressBook database
IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = N'AddressBook')
BEGIN
  CREATE DATABASE AddressBook;
END;
GO

USE AddressBook;
GO

-- Create the Contacts table
IF OBJECT_ID(N'Contacts', N'U') IS NULL
BEGIN
    CREATE TABLE Contacts
    (
        Id        INT PRIMARY KEY IDENTITY(1,1) ,
        FirstName VARCHAR(255) NOT NULL,
        LastName  VARCHAR(255) NOT NULL,
        Email     VARCHAR(255) NULL,
        Phone     VARCHAR(255) NULL
    );
END;
GO

-- Ensure that either the Email or Phone column is populated
IF OBJECT_ID(N'chk_Contacts_Email_Phone', N'C') IS NULL
BEGIN
    ALTER TABLE Contacts
    ADD CONSTRAINT chk_Contacts_Email_Phone CHECK
    (
        Email IS NOT NULL OR Phone IS NOT NULL
    );
END;
GO

-- Insert some sample data into the Contacts table
IF (SELECT COUNT(*) FROM Contacts) = 0
BEGIN
    INSERT INTO Contacts (FirstName, LastName, Email, Phone)
    VALUES
        ('John', 'Doe', 'john.doe@example.com', '555-123-4567'),
        ('Jane', 'Doe', 'jane.doe@example.com', '555-234-5678');
END;
GO

必须确保将此脚本复制到应用主机的输出目录,以便 .NET.NET Aspire 可以执行该脚本。 将以下 XML 添加到 .csproj 文件:

<ItemGroup>
  <None Include="..\DatabaseContainers.ApiService\data\sqlserver\init.sql" Link="init.sql">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
</ItemGroup>

请调整Include参数以匹配项目中 SQL 脚本的路径。

接下来,在应用主机 的AppHost.cs (或 Program.cs)文件中,创建数据库并运行创建脚本:

var sqlserver = builder.AddSqlServer("sqlserver")
    // Configure the container to store data in a volume so that it persists across instances.
    .WithDataVolume()
    // Keep the container running between app host sessions.
    .WithLifetime(ContainerLifetime.Persistent);

// Add the database to the application model so that it can be referenced by other resources.
var initScriptPath = Path.Join(Path.GetDirectoryName(typeof(Program).Assembly.Location), "init.sql");
var addressBookDb = sqlserver.AddDatabase("AddressBook")
    .WithCreationScript(File.ReadAllText(initScriptPath));

前面的代码:

  • 通过调用SQL Server创建builder.AddSqlServer()容器。
  • 通过调用 WithDataVolume()WithLifetime(ContainerLifetime.Persistent)调用,确保在调试会话之间保留数据。
  • 获取输出文件夹中 T-SQL 脚本的路径。
  • 调用 WithCreationScript() 创建并填充数据库。

使用 EF Core 初始化数据

还可以在启动时显式运行迁移,通过 .NET Aspire 在 EF Core 项目中设定种子数据。 EF Core 可处理基础数据库连接和架构创建,因此无需在容器启动期间使用卷或运行 SQL 脚本。

重要

这些类型的配置只能在开发期间完成,因此请确保添加用于检查当前环境上下文的条件。

将以下代码添加到 Program.cs 项目的 文件中。

// Register DbContext class
builder.AddSqlServerDbContext<TicketContext>("sqldata");

var app = builder.Build();

app.MapDefaultEndpoints();

if (app.Environment.IsDevelopment())
{
    // Retrieve an instance of the DbContext class and manually run migrations during startup
    using (var scope = app.Services.CreateScope())
    {
        var context = scope.ServiceProvider.GetRequiredService<TicketContext>();
        context.Database.Migrate();
    }
}

后续步骤

数据库初始化在各种应用开发场景中非常有用。 请尝试将这些技术与以下教程中演示的资源实现相结合: