我有一个ASP.NET MVC 6应用程序,我需要调用Database.EnsureCreated
和Database.Migrate
方法。
但是我应该在哪里打电话呢?
Answers:
我认为这是一个重要的问题,应该得到很好的回答!
什么是Database.EnsureCreated?
context.Database.EnsureCreated()
是一种新的EF核心方法,可确保上下文数据库存在。如果存在,则不采取任何措施。如果它不存在,那么将创建数据库及其所有架构,并确保该数据库与该上下文的模型兼容。
注意:
此方法不使用迁移来创建数据库。此外,创建的数据库以后无法使用迁移进行更新。如果您以关系数据库为目标并使用迁移,则可以使用该DbContext.Database.Migrate()
方法来确保创建数据库并应用所有迁移。
我们如何使用EF 6做到这一点?
context.Database.EnsureCreated()
等效于下面列出的EF 6方法:
程序包管理器控制台:
Enable-Migrations -EnableAutomaticMigrations。添加迁移/更新数据库。
来自代码:
Database.SetInitializer CreateDatabaseIfNotExists
要么
使用DbMigrationsConfiguration并设置AutomaticMigrationsEnabled = true;
什么是Database.Migrate?
将上下文的所有未决迁移应用到数据库。如果尚不存在,将创建数据库。
我们如何使用EF 6做到这一点?
context.Database.Migrate()
等效于下面列出的EF 6方法:
程序包管理器控制台:
更新数据库-TargetMigration
使用自定义DbMigrationsConfiguration:
AutomaticMigrationsEnabled = false; 或使用DbMigrator。
结论:
如果您正在使用迁移,则有context.Database.Migrate()
。如果您不希望迁移,而只是想要一个快速数据库(通常用于测试),则可以使用context.Database.EnsureCreated()/ EnsureDeleted()。
Database.Migrate()
迁移(如果需要),然后根据其更新基础。类似于EF 6中的自动迁移。但是我错了。它仅在数据库上应用现有迁移(如果有)。
有了James P和Bassam Alugili提供的信息,我最终要做的是将这些代码行添加到类(Startup.cs)中的Configure
方法中:Startup
using (var scope =
app.ApplicationServices.CreateScope())
using (var context = scope.ServiceProvider.GetService<MyDbContext>())
context.Database.Migrate();
正如foreward你应该阅读这从罗恩·米勒:
...
EnsureCreated
完全绕开了迁移,只是为您创建了架构,您不能将其与迁移混在一起。EnsureCreated
专为测试或快速原型设计,您可以每次删除并重新创建数据库。如果您正在使用迁移,并希望在应用启动时自动应用它们,则可以context.Database.Migrate()
改用。
根据这里的答案,您需要将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();
}
Globals
。这看起来像是尝试撬起的非标准方式
通常,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
尚未在当前作用域()之前在注入容器中注册,因此Startup.ConfigureServices
我们无法在此处通过依赖项注入访问上下文。
Henk Mollema在此处讨论了启动过程中的手动解决服务,但提到了...
手动解决服务(又称为服务定位器)通常被认为是一种反模式... [并且]您应尽可能避免使用它。
Henk还提到,Startup
构造函数的依赖项注入非常有限,并且不包含在中配置的服务Startup.ConfigureServices()
,因此DbContext的用法最简单,并且最适合在应用程序其余部分中使用的注入容器。
运行时的托管服务提供程序可以将某些服务注入到
Startup
类的构造函数中,例如IConfiguration
,IWebHostEnvironment
(IHostingEnvironment
在3.0之前的版本中)ILoggerFactory
和IServiceProvider
。请注意,后者是由托管层构建的实例,并且仅包含用于启动应用程序的基本服务。
为了调用Database.EnsureCreated()
或Database.Migrate()
,我们可以并且希望在中自动解析DbContext Startup.Configure()
,现在可以通过DI使用我们已配置的服务:
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();
}
}
}
请记住,EF核心文档中引用了Bassam Alugili的答案Database.EnsureCreated()
,Database.Migrate()
但不能一起使用,因为这样可以确保将现有迁移应用于需要创建的数据库。另一个只是确保数据库存在,如果不存在,则创建一个反映您的数据库DbContext
,包括通过上下文中的Fluent API完成的任何种子设置。