.NET 6 如何 运行 在 program.cs 中自动迁移

.NET 6 how to run Migration automatically in program.cs

在 .Net 5 中,我们过去可以通过将 DataContext 传递给 Configure 方法来调用迁移,并在启动时调用迁移 class。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, DataContext dataContext)
{
    // migrate any database changes on startup (includes initial db creation)
    dataContext.Database.Migrate();

    ...
}

我们如何在 .Net 6 中做到这一点?

精简版

听起来真正的问题是将曾经存在于 Startup.Configure 中的代码放在哪里。

Program.cs中使用

using (var scope = app.Services.CreateScope())
{
    var db = scope.ServiceProvider.GetRequiredService<SomeDbContext>();
    db.Database.Migrate();
}

相当长的解释

EF Core 迁移文档中的 Applying Migrations at Runtime 部分显示,就 EF Core 而言,没有任何变化。

public static void Main(string[] args)
{
    var host = CreateHostBuilder(args).Build();

    using (var scope = host.Services.CreateScope())
    {
        var db = scope.ServiceProvider.GetRequiredService<SomeDbContext>();
        //Same as the question
        db.Database.Migrate();
    }

    host.Run();
}

听起来真正的问题是将曾经存在于 Startup.Configure 中的代码放在哪里。该代码可以放在 Main 方法中,或者如果使用 Minimal APIs,则放在 Program.cs 中。 ConfigurationServicesEnvironment 等可作为其创建的 WebApplicationBuilder class or the WebApplication 中的属性使用。 WebApplicationBuilder 包含用于 DI、配置、日志记录和主机的构建器接口,例如 WebApplicationBuilder.Services 公开 IServiceCollection

WebApplication 属性公开由 WebApplicationBuilder 配置的中间件,例如 WebApplication.Services 公开 IServiceProvider

以最小 APIs

启动替换

.NET 6 中 Startup.cs 中的方法已合并到 Program.cs 中。Startup.cs 包含两种方法:

  • 通过调用 IServiceCollectionIConfigurationBuilder 等各种构建器接口来配置主机和应用程序的方法,例如设置配置和 DI。这包括曾经在 Startup.ConfigureServices.
  • 中的代码
  • 使用主机配置端点、使用服务和中间件的方法。这包括 Startup.Configure.
  • 中的代码

在 .NET 6 中,接口移动到 WebApplicationBuilder 和 WebApplication classes。 Program.cs 中的代码可以直接访问它需要的接口,而不是 .NET Core 调用“神奇的”Startup class 并注入接口。

  • 主机 building/configuration 服务现在可以通过 WebApplicationBuilder class 获得。
  • 完整的应用程序宿主提供的接口现在可以通过由 WebApplicationBuilder 构建的 WebApplication class 获得。

如果您不需要配置服务,您可以只用 3 行创建一个最小的 API 应用程序:

var app = WebApplication.Create(args);

app.MapGet("/", () => "Hello World!");

app.Run();

在您的情况下,您至少需要配置 DbContext,因此您需要分别使用 WebApplicationBuilderWebApplication。这将在下一节中显示

最小迁移 APIs

基本最小APIProgram.cs:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

一旦通过 Services 属性:

创建了 WebApplication 实例,就可以创建 DbContexts
var builder = WebApplication.CreateBuilder(args);
//Register the DbContexts etc.
...
builder.Services.AddDbContext<SomeDbContext>(....);

var app = builder.Build();

using (var scope = app.Services.CreateScope())
{
    var db = scope.ServiceProvider.GetRequiredService<SomeDbContext>();
    db.Database.Migrate();
}

app.MapGet("/", () => "Hello World!");

app.Run();

当然 很多 更好地使用单独的方法或 classes 此类代码,保持 Program.cs 干净:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<SomeDbContext>(....);
var app = builder.Build();

ApplyMigrations(app);

app.MapGet("/", () => "Hello World!");

app.Run();

static void ApplyMigrations(WebApplication app)
{
    using var scope = app.Services.CreateScope();
    var db = scope.ServiceProvider.GetRequiredService<SomeDbContext>();
    db.Database.Migrate();
}

甚至:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<SomeDbContext>(....);
var app = builder.Build();

app.ApplyMigrations()
   .UseCustomLogging()
   .DoSomeOtherConfiguration()
   ...;

app.MapGet("/", () => "Hello World!");

app.Run();

使用 ApplyMigrations 单独的扩展方法 class :

public static DataExtensions
{
    public static WebApplication ApplyMigrations(this WebApplication app)
    {
        using var scope = app.Services.CreateScope()
        var db = scope.ServiceProvider.GetRequiredService<SomeDbContext>();
        db.Database.Migrate();
        return app;
    }
}

在ASP.NET核心6中,应该是:

using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<YourDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("YourConnectionString")));
     
var app = builder.Build();
using (var scope = app.Services.CreateScope())
{
    var db = scope.ServiceProvider.GetRequiredService<YourDbContext>();
    db.Database.Migrate();
}