如何以及在何处调用 Database.EnsureCreated 和 Database.Migrate?
Posted
技术标签:
【中文标题】如何以及在何处调用 Database.EnsureCreated 和 Database.Migrate?【英文标题】:How and where to call Database.EnsureCreated and Database.Migrate? 【发布时间】:2016-11-09 08:00:27 【问题描述】:我有一个 ASP.NET MVC 6 应用程序,我需要调用 Database.EnsureCreated
和 Database.Migrate
方法。
但是我应该在哪里给他们打电话呢?
【问题讨论】:
您可能也不想使用。 MS 文档这样说关于使用 Migrate():“虽然它对于具有本地数据库的应用程序来说非常棒,但大多数应用程序将需要更强大的部署策略,例如生成 SQL 脚本。” docs.microsoft.com/en-us/ef/core/managing-schemas/migrations 【参考方案1】:我认为这是一个重要的问题,应该很好地回答!
什么是 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()。
【讨论】:
您好 Bassam Alugili,感谢您的回答!在我的项目中,我正在使用迁移,我不知道不应该同时使用这两种方法。 uw 这是一个如何调用它的例子! stefanhendriks.com/2016/04/29/… 我在想Database.Migrate()
创建迁移(如果需要)然后更新基于它的基础。就像 EF 6 中的自动迁移一样。但我错了。它仅在数据库上应用现有迁移(如果有)。
据我了解,Database.Migrate 在对数据库执行插入/查询等操作时使用应用程序使用的相同数据库信用。我们是否希望这些操作由具有创建/删除权限的用户完成?这有办法让 Database.Migrate() 使用其他信用(具有创建/删除权限)?
你刚刚把我从未来的灾难中救了出来。 赞【参考方案2】:
根据 James P 和 Bassam Alugili 提供的信息,我最终将这些代码行添加到 Startup
类中的 Configure
方法 (Startup.cs) :
using (var scope =
app.ApplicationServices.CreateScope())
using (var context = scope.ServiceProvider.GetService<MyDbContext>())
context.Database.Migrate();
【讨论】:
这正是我想要的。大多数示例使用 .Net 核心或 Web,而我使用的是 .Net 4.6 的 Windows 窗体应用程序。数据库已创建(因为连接字符串中的用户无权创建数据库)。上面的代码创建了迁移中的所有表和所有内容。 对不起,这是我认为与本案有关的问题的链接:***.com/questions/70512142/…。你能看看它,看看你的 sulotion 对我有没有帮助?如果没有,你能给我一些解决问题的方法吗? 在 .NET 6 Startup.cs 中不再存在。我们有关于现在在哪里使用它的更新吗?【参考方案3】:作为前锋,您应该阅读 Rowan Miller 的 this:
...
EnsureCreated
完全绕过迁移,只创建 为您提供架构,您不能将其与迁移混合使用。EnsureCreated
是 专为测试或快速原型设计而设计 每次删除并重新创建数据库。如果您正在使用 迁移并希望在应用启动时自动应用它们, 那么你可以改用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()
,请参阅here 或here。
【讨论】:
你好 James,谢谢你的回答!,我在我的启动方法中没有任何访问变量名 Globals 的权限,我怎样才能访问它? 同样,没有看到Globals
。这看起来像是一种试图在中撬开它的非标准方式
据我了解,标准方式是在 Startup.ConfigureServices 中创建 DbContext,但通过某种间接方法。您可以将其重新放回原处,或在 Startup.Configure 中使用 app.ApplicationServices.GetRequiredService通常,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 讨论了在启动期间手动解析服务 here,但提到...
手动解析服务(又名服务定位器)是generally considered an anti-pattern ... [并且] 你应该尽可能避免它 尽可能。
Henk 还提到Startup
构造函数的依赖注入非常有限,不包括在Startup.ConfigureServices()
中配置的服务,因此通过在整个应用程序中使用的注入容器,DbContext 的使用是最简单和最合适的。
运行时的托管服务提供者可以将某些服务注入到
Startup
类的构造函数中,例如IConfiguration
、IWebHostEnvironment
(3.0之前的版本为IHostingEnvironment
)、ILoggerFactory
和IServiceProvider
。请注意,后者是托管层构建的实例,仅包含启动应用程序的基本服务。
为了调用Database.EnsureCreated()
或Database.Migrate()
,我们可以并且希望在Startup.Configure()
中自动解析 DbContext,我们配置的服务现在可以通过 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();
请记住 Bassam Alugili's answer 引用自 EF Core 文档,Database.EnsureCreated()
和 Database.Migrate()
不能一起使用,因为它们可以确保将现有迁移应用到数据库,该数据库是在需要时创建的。另一个只是确保数据库存在,如果不存在,则创建一个反映您的 DbContext
的数据库,包括通过上下文中的 Fluent API 完成的任何播种。
【讨论】:
我发现在内存数据库中播种的最优雅的方式,谢谢 这是种内存数据库的一种非常聪明的方法。谢谢。【参考方案5】:此外,如果您在上下文的构造函数中调用它,您可能会看到性能下降...在将 EnsureCreated
移动到 setup.cs 实用程序后,我注意到响应时间有了相当大的改进。
注意:我使用的是 EFC 和 UWP。
【讨论】:
【参考方案6】:var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddDbContext<YourDbContext>(option => option.UseSqlServer(@"Data source=(localdb)\ProjectModels;Initial Catalog=YourDb;Integrated Security=True"));
var app = builder.Build();
// Configure the HTTP request pipeline.
YourDbContext dbcontext = app.Services.GetRequiredService<YourDbContext>();
dbcontext.Database.EnsureCreated();
【讨论】:
以上是关于如何以及在何处调用 Database.EnsureCreated 和 Database.Migrate?的主要内容,如果未能解决你的问题,请参考以下文章
__eq__ 在 Python 中是如何处理的以及按啥顺序处理?
htmlspecialchars() 或 如何以及在何处使用?