使用单独的迁移项目

可以将迁移存储在包含你的 DbContext项目的不同项目中。 当应用程序项目特定于平台(例如 WinUI、.NET MAUI、Blazor WebAssembly 或 Azure Functions)或面向特定运行时标识符(RID)时,建议这样做。 它还可用于维护多个迁移集。

Tip

可以在 GitHub 上查看本文的 示例。

项目布局

此示例使用三个项目:

项目 责任 参考
WebApplication1.Data DbContext拥有和实体类型 EF Core 提供程序
WebApplication1.Migrations 拥有迁移、模型快照和设计时上下文创建 数据项目、EF Core 提供程序和 Microsoft.EntityFrameworkCore.Design
WebApplication1 运行应用程序 数据项目和迁移项目

应用程序在运行时发现或应用迁移时需要引用迁移项目,例如通过调用 Migrate。 如果迁移仅由部署项目应用,并且应用程序永远不会加载它们,则不需要该引用。

配置项目

  1. 为迁移创建类库,并添加对包含 <a0/> 的项目的引用。

  2. 将数据库提供程序添加到 Microsoft.EntityFrameworkCore.Design 迁移项目。 将设计包标记为专用开发依赖项:

    <ItemGroup>
      <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="...">
        <PrivateAssets>all</PrivateAssets>
        <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      </PackageReference>
      <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="..." />
    </ItemGroup>
    
    <ItemGroup>
      <ProjectReference Include="..\WebApplication1.Data\WebApplication1.Data.csproj" />
    </ItemGroup>
    
  3. 在迁移项目中实现 IDesignTimeDbContextFactory<TContext> 。 工厂允许工具创建上下文,而无需运行应用程序项目:

    public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
    {
        public ApplicationDbContext CreateDbContext(string[] args)
        {
            var connectionString = args.FirstOrDefault()
                ?? @"Server=(localdb)\mssqllocaldb;Database=WebApplication1;Trusted_Connection=True";
    
            var options = new DbContextOptionsBuilder<ApplicationDbContext>()
                .UseSqlServer(
                    connectionString,
                    sqlServer => sqlServer.MigrationsAssembly(typeof(ApplicationDbContextFactory).Assembly.GetName().Name))
                .Options;
    
            return new ApplicationDbContext(options);
        }
    }
    

    使设计时提供程序和模型配置与运行时配置保持一致。 该示例接受可选的连接字符串参数,并在未提供任何参数时使用本地开发连接。

  4. 在运行时注册上下文时配置迁移程序集:

    services.AddDbContext<ApplicationDbContext>(
        options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection"),
                x => x.MigrationsAssembly("WebApplication1.Migrations")));
    
  5. 如果应用程序应用迁移或在运行时发现迁移,请将应用程序的常规引用添加到迁移项目:

    <ItemGroup>
      <ProjectReference Include="..\WebApplication1.Migrations\WebApplication1.Migrations.csproj" />
    </ItemGroup>
    

    数据项目不得引用迁移项目。 这将创建循环依赖项,因为迁移项目已经引用了数据项目。

  6. 如果迁移已存在,请将所有迁移文件和模型快照移动到迁移项目并更新其命名空间。 如果没有现有迁移,设计时工厂允许直接在迁移项目中创建初始迁移。

请使用工具

将迁移项目用作 目标项目和启动项目。 目标项目接收生成的文件,而启动项目由工具生成和执行。 在此布局中,将迁移项目用于这两者都可防止工具执行应用程序启动代码。

从解决方案目录运行以下命令:

dotnet ef migrations add NewMigration \
    --project WebApplication1.Migrations \
    --startup-project WebApplication1.Migrations

相同的项目选项适用于其他命令:

dotnet ef migrations list \
    --project WebApplication1.Migrations \
    --startup-project WebApplication1.Migrations

dotnet ef migrations script --output artifacts/migrations.sql \
    --project WebApplication1.Migrations \
    --startup-project WebApplication1.Migrations

dotnet ef migrations bundle --output artifacts/efbundle \
    --project WebApplication1.Migrations \
    --startup-project WebApplication1.Migrations

从 EF Core 11 开始,重复的项目选项可以存储在其中 .config/dotnet-ef.json

在运行命令 --no-build之前或在另一个进程使用其输出之前生成迁移项目。 普通 dotnet ef 命令会自动生成目标和启动项目。

特定于平台的应用程序

不要将特定于平台的应用程序项目用作 EF 工具的启动项目。 移动、浏览器、桌面、函数和 RID 特定的项目可能需要无法执行的工作负荷或本机主机 dotnet ef 。 从 EF Core 11 开始,工具会在使用特定于平台的启动项目时发出警告。

将上述布局用于.NET MAUI、WinUI、Blazor WebAssembly、Azure Functions和类似的应用程序:

  1. 将上下文和实体类型放入共享数据项目中。
  2. 将迁移置于IDesignTimeDbContextFactory<TContext>正常的跨平台.NET项目中。
  3. 使用迁移项目作为目标和启动项目运行工具。
  4. 仅当应用程序在运行时加载或应用迁移时,才从应用程序引用迁移项目。

未计划Xamarin和 MAUI 平台项目的直接工具支持;请参阅 dotnet/efcore#7152。 应首先将Xamarin应用程序升级到.NET MAUI

流程体系结构

运行工具的进程必须能够加载每个设计时程序集。 64 位Visual Studio或.NET进程无法加载仅限 x86 的启动程序集,并且相同的约束适用于 Arm64 和其他体系结构。 首选 AnyCPU 迁移项目。 如果设计时依赖项需要特定的体系结构,请显式调用匹配.NET SDK。

设计时过程体系结构与部署目标不同。 创建捆绑包时,请使用 --target-runtime-TargetRuntime 生成部署 RID 的项目,例如 linux-arm64osx-arm64