如何以及在何处调用Database.EnsureCreated和Database.Migrate?

时间:2016-07-07 05:24:53

标签: asp.net asp.net-mvc entity-framework entity-framework-core

我有一个ASP.NET MVC 6应用程序,我需要调用Database.EnsureCreated和Database.Migrate方法。

但我应该在哪里打电话给他们?

5 个答案:

答案 0 :(得分:57)

我认为这是一个重要的问题,应该得到很好的回答!

什么是Database.EnsureCreated?

context.Database.EnsureCreated()是新的EF核心方法,可确保上下文的数据库存在。如果存在,则不采取任何措施。如果它不存在,则创建数据库及其所有模式,并确保它与此上下文的模型兼容。

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

我们是如何使用EF 6做到的?

context.Database.EnsureCreated()等同于下面列出的EF 6的方法:

  1. 软件包管理器控制台:

    启用 - 迁移-EnableAutomaticMigrations。添加迁移/更新的数据库。

  2. 来自代码:

    Database.SetInitializer CreateDatabaseIfNotExists

  3. 使用DbMigrationsConfiguration并设置AutomaticMigrationsEnabled = true;

    什么是Database.Migrate?

    将上下文的任何挂起的迁移应用于数据库。如果数据库尚不存在,将创建数据库。

    我们是如何使用EF 6做到的?

    context.Database.Migrate()等同于下面列出的EF 6的方法:

    1. 软件包管理器控制台:

      更新 - 数据库-TargetMigration

    2. 使用自定义DbMigrationsConfiguration:

      AutomaticMigrationsEnabled = false;或者使用DbMigrator。

    3. <强>结论

      如果您使用迁移,则context.Database.Migrate()。如果您不想迁移并且只想要一个快速数据库(通常用于测试),那么请使用context.Database.EnsureCreated()/ EnsureDeleted()。

答案 1 :(得分:11)

根据James P和Bassam Alugili提供的信息,我最终做的是将这行代码添加到Startup.cs-&gt; Configure方法中。

using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>()
    .CreateScope())
{

    serviceScope.ServiceProvider.GetService<ApplicationDbContext>()
        .Database.Migrate();
}

答案 2 :(得分:10)

正如前言你应该阅读Rowan Miller的this

  

... EnsureCreated完全绕过迁移并创建了   架构适合您,您不能将其与迁移混合使用。 EnsureCreated是   专为测试或快速原型设计而设计   每次都删除并重新创建数据库。如果你正在使用   迁移并希望在app start上自动应用它们,   那么你可以改用context.Database.Migrate()

根据回答here,您需要将Globals.EnsureDatabaseCreated();添加到Startup.cs

Startup.cs 中的启动功能:

public Startup(IHostingEnvironment env)
{
    // Set up configuration sources.
    var builder = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json")
            .AddEnvironmentVariables();

    if (env.IsDevelopment())
    {
        // This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
            builder.AddApplicationInsightsSettings(developerMode: true);
    }
    Configuration = builder.Build();
    Globals.Configuration = Configuration;
    Globals.HostingEnvironment = env;
    Globals.EnsureDatabaseCreated();
}

定义Globals.EnsureDatabaseCreated()如下:

public static void EnsureDatabaseCreated()
    {
        var optionsBuilder = new DbContextOptionsBuilder();
        if (HostingEnvironment.IsDevelopment()) optionsBuilder.UseSqlServer(Configuration["Data:dev:DataContext"]);
        else if (HostingEnvironment.IsStaging()) optionsBuilder.UseSqlServer(Configuration["Data:staging:DataContext"]);
        else if (HostingEnvironment.IsProduction()) optionsBuilder.UseSqlServer(Configuration["Data:live:DataContext"]);
        var context = new ApplicationContext(optionsBuilder.Options);
        context.Database.EnsureCreated();

        optionsBuilder = new DbContextOptionsBuilder();
        if (HostingEnvironment.IsDevelopment()) optionsBuilder.UseSqlServer(Configuration["Data:dev:TransientContext"]);
        else if (HostingEnvironment.IsStaging()) optionsBuilder.UseSqlServer(Configuration["Data:staging:TransientContext"]);
        else if (HostingEnvironment.IsProduction()) optionsBuilder.UseSqlServer(Configuration["Data:live:TransientContext"]);
        new TransientContext(optionsBuilder.Options).Database.EnsureCreated();
    }

要使用context.Database.Migrate(),请参阅herehere

答案 3 :(得分:7)

通常,DbContext将被添加到Startup.ConfigureServices()中的依赖项注入容器中,如下所示:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        // Add DbContext to the injection container
        services.AddDbContext<MyDbContext>(options =>
                options.UseSqlServer(
                    this.Configuration.GetConnectionString("DefaultConnection")));
    }
}

但是,IServiceCollection并不充当服务提供者,并且由于DbContext尚未在当前作用域 之前注册到注入容器中({{1 }}),我们不能在这里通过依赖注入来访问上下文。

Henk Mollema讨论了在启动here期间手动解决服务的问题,但提到了...

手动解析服务(又称服务定位器)为generally considered an anti-pattern ... [并且]您应尽量避免使用它 尽可能。

Henk还提到Startup.ConfigureServices构造函数的依赖项注入非常有限,并且不包括在Startup中配置的服务,因此DbContext的用法最简单,并且最适合在其余的其余部分中使用的注入容器。应用程序。

运行时的托管服务提供商可以将某些服务注入Startup.ConfigureServices()类的构造函数中,例如StartupIConfiguration(3.0之前的版本为IWebHostEnvironment), IHostingEnvironmentILoggerFactory。请注意,后者是由托管层构建的实例,并且仅包含用于启动应用程序的基本服务。

为了调用IServiceProviderDatabase.EnsureCreated(),我们可以并且希望在Database.Migrate()中自动解析DbContext,现在可以通过DI使用我们已配置的服务:

Startup.Configure()

请记住,从EF Core文档中引用的Bassam Alugili's answer来看,public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // Add DbContext to the injection container services.AddDbContext<MyDbContext>(options => options.UseSqlServer( this.Configuration.GetConnectionString("DefaultConnection"))); } public static void Configure(IApplicationBuilder app, IWebHostEnvironment env, MyDbContext context) { if (env.IsDevelopment()) { context.Database.EnsureCreated(); //context.Database.Migrate(); } } } Database.EnsureCreated()不能一起使用,因为这可以确保将现有迁移应用于创建的数据库如果需要的话。另一个只是确保数据库存在,如果不存在,则创建一个反映您的Database.Migrate()的数据库,包括通过上下文中Fluent API完成的种子。

答案 4 :(得分:0)

此外,如果您在上下文的构造函数中调用它,您可能会看到性能损失...将for i : CGFloat in stride(from: 1.0, through: 40.0, by: 1.0) { let angle = 2 * .pi / i print(angle) } 移动到setup.cs实用程序后,我发现响应时间有了相当大的改进。

注意:我正在使用EFC和UWP。