ASP - Core在启动时迁移EF Core SQL DB

Zeu*_*s82 49 c# entity-framework-core asp.net-core

是否可以让我的ASP Core Web API确保使用EF Core将数据库迁移到最新的迁移?我知道这可以通过命令行完成,但我想以编程方式完成.

更新

根据Janshair Khan的回答,我提出了这个助手类:

using Microsoft.AspNetCore.Builder;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using MyWebApi.Models;

namespace MyWebApi
{
    public static class DataSeeder
    {
        public static void SeedData(this IApplicationBuilder app)
        {
            var context = app.ApplicationServices.GetService<MyContext>();

            if (!context.Database.EnsureCreated())
                context.Database.Migrate();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以通过以下Configure方法调用此方法Startup.cs:

app.SeedData();
Run Code Online (Sandbox Code Playgroud)

ste*_*lla 38

关于致电的文件的说明db.Database.EnsureCreated():

请注意,此API不使用迁移来创建数据库.此外,以后无法使用迁移更新创建的数据库.如果要定位关系数据库并使用迁移,则可以使用DbContext.Database.Migrate()方法确保创建数据库并应用所有迁移.

你可能只想打电话db.Database.Migrate().

从上面的声明中获取的评论来自此处.


Jan*_*han 28

您可以使用

db.Database.EnsureCreated();
Run Code Online (Sandbox Code Playgroud)

让您的数据库与您当前的模型保持同步.如果要启用迁移(如果怀疑后续迁移),请使用

db.Database.Migrate();
Run Code Online (Sandbox Code Playgroud)

并随着时间的推移进行后续迁移.

  • @Floxy我认为你错过了`使用Microsoft.EntityFrameworkCore;`. (3认同)
  • ensureCreated() 工作正常但是“context.Database.Migrate()”没有 Migrate() 方法为什么会这样?英孚核心 (2认同)
  • 在 ASP.NET Core 应用程序中调用“Database.Migrate”的正确位置在哪里? (2认同)

小智 14

使用以下代码运行迁移

public async void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
    {
        var context = serviceScope.ServiceProvider.GetService<YourContext`enter code here`>();
        context.Database.Migrate();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 从 .NET Core 2.1 升级到 3.0(并且隐式地从进程外托管升级到进程内托管)后,从启动中调用“Migrate”对我来说不再起作用。如果没有错误消息,网络应用程序将无法启动。我将该项目标记为“&lt;AspNetCoreHostingModel&gt;OutOfProcess&lt;/AspNetCoreHostingModel&gt;”,然后它再次工作。 (3认同)

Jas*_*son 14

这在 ASP.NET Core 3.1 中对我有用,只需在Configure方法中注册后将db 上下文作为参数注入现有ConfigureServices方法。

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<DataContext>(x => x.UseSqlite("Data Source=LocalDatabase.db"));

    ...
}
Run Code Online (Sandbox Code Playgroud)
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, DataContext dataContext)
{
    dataContext.Database.Migrate();

    ...
}
Run Code Online (Sandbox Code Playgroud)

更多详细信息和完整代码示例链接,请访问https://jasonwatmore.com/post/2019/12/27/aspnet-core-automatic-ef-core-migrations-to-sql-database-on-startup


pis*_*ker 7

基于@steamrolla的答案,我将提出以下改进:

public static class EnsureMigration
{
    public static void EnsureMigrationOfContext<T>(this IApplicationBuilder app) where T:DbContext
    {
        var context = app.ApplicationServices.GetService<T>();
        context.Database.Migrate();
    }
}
Run Code Online (Sandbox Code Playgroud)

这样,您还可以确保迁移不同的上下文,例如,如果您有一个身份数据库。

用法:

app.EnsureMigrationOfContext<context>();
Run Code Online (Sandbox Code Playgroud)


Sve*_*ven 6

我遵循该IStartupFilter方法来获得迁移任何上下文的通用方法。

 public class DataContextAutomaticMigrationStartupFilter<T> : IStartupFilter
  where T : DbContext
{
    /// <inheritdoc />
    public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
    {
        return app =>
        {
            using (var scope = app.ApplicationServices.CreateScope())
            {
                scope.ServiceProvider.GetRequiredService<T>().Database.SetCommandTimeout(160);
                scope.ServiceProvider.GetRequiredService<T>().Database.Migrate();
            }
            next(app);
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以通过以下方式注册 DataContext 和迁移:

第一个上下文

 services.AddDbContext<ConsumerDataContext>(options => options.UseSqlServer(configuration.GetConnectionString("ConsumerConnection")), ServiceLifetime.Transient);
    services.AddTransient<IStartupFilter, DataContextAutomaticMigrationStartupFilter<ConsumerDataContext>>();
Run Code Online (Sandbox Code Playgroud)

第二个背景

services.AddDbContext<UserDataContext>(options => options.UseSqlServer(configuration.GetConnectionString("UserConnection")), ServiceLifetime.Transient);
services.AddTransient<IStartupFilter, DataContextAutomaticMigrationStartupFilter<UserDataContext>>();
Run Code Online (Sandbox Code Playgroud)

..等等..

罪魁祸首IStartupFilter是它只允许同步执行代码。对于数据库迁移来说这不是问题,因为我们有同步Migrate()方法。


Faz*_*edi 6

在Asp core 6中没有StartUp,在以前版本的asp中我们有Configure方法,它允许直接访问ServiceProvider,然后我们可以使用GetServices来获取DBcontext,然后调用Migrate方法。

但现在在 Asp core 6 中。我们应该创建一个范围,然后获取 DBcontext 对象

        using (var Scope = app.services.CreateScope())
        {
            var context = Scope.Services.GetRequireService<DBContext>();
            context.Database.Migrate();
        }
Run Code Online (Sandbox Code Playgroud)


umu*_*sen 5

根据chintan310的回答,这是我迁移数据库的方法。这确保将与数据库相关的任务分离为Program.cs

    public static void Main(string[] args)
    {
        var host = BuildWebHost(args);

        using (var scope = host.Services.CreateScope())
        {
            var services = scope.ServiceProvider;

            try
            {
                var context = services.GetService<AppDbContext>();
                context.Database.Migrate();

                var seeder = scope.ServiceProvider.GetService<AppSeeder>();
                seeder.Seed().Wait();
            }
            catch (Exception ex)
            {
                var logger = services.GetRequiredService<ILogger<Program>>();
                logger.LogError(ex, "An error occurred seeding the DB.");
            }
        }

        host.Run();
    }

    private static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .Build();
Run Code Online (Sandbox Code Playgroud)


Igo*_*gor 5

此代码适用于.NET core 3.0

 using (var scope = app.ApplicationServices.CreateScope())
 {
     var dbContext = scope.ServiceProvider.GetService<T>();
     dbContext.Database.Migrate();
 }
Run Code Online (Sandbox Code Playgroud)


Shi*_*mmy 5

使用 C# 7.1 启动 .NET Core 2,您的应用程序可以使用异步Main方法,因此您可以在运行主机之前、在主机完成构建之后调用所有初始化逻辑:

public class Program
{
  public static async Task Main(string[] args)
  {
    //first build
    var host = CreateHostBuilder(args).Build();

    //initialize
    using (var serviceScope = host.Services.CreateScope())
    {
      var serviceProvider = serviceScope.ServiceProvider;
      var isDevelopment = 
        serviceProvider.GetRequiredService<IWebHostEnvironment>().IsDevelopment();

      using var context = serviceProvider.GetRequiredService<AppDbContext>();


      if (isDevelopment)
        await context.Database.EnsureCreatedAsync();
      else
        await context.Database.MigrateAsync();

      if (isDevelopment)
      {
        using var userManager = 
          serviceProvider.GetRequiredService<UserManager<AppUser>>();
        await userManager
          .CreateAsync(new AppUser { UserName = "dummy", Email = "dummy@dumail.com" },
          password: "1234");
      }
    }

    //now run
    host.Run();
  }

  public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
      .ConfigureWebHostDefaults(webBuilder =>
      {
        webBuilder.UseStartup<Startup>();
      });
}
Run Code Online (Sandbox Code Playgroud)


Ali*_*odi 5

Program.cs 在 EF Core 7 中,您可以按照以下方式立即执行var app = builder.Build();此操作:

using (var Scope = app.Services.CreateScope())
{
    var context = Scope.ServiceProvider.GetRequiredService<AppDbContext>();
    context.Database.Migrate();
}
Run Code Online (Sandbox Code Playgroud)

祝您编码愉快,别忘了投票;)