EF 5,代码优先——创建一个新数据库,并以编程方式运行所有迁移
本文关键字:编程 数据库 方式 运行 迁移 代码 创建 EF 一个 | 更新日期: 2023-09-27 18:06:36
我正在使用实体框架代码优先迁移,并且我有一个场景,我想运行一套集成测试。每次测试运行时,我都想重新创建数据库,并应用所有迁移
步骤如下:
- 删除现有的测试数据库(如果有)
- 创建一个新的测试数据库,并应用所有迁移 <
- 种子数据/gh>
这是一个我已经添加了迁移的现有项目,我使用Enable-Migrations命令创建了一个"InitialCreate"迁移,其中包含将所有表添加到数据库的代码。
我的自定义IDatabaseInitializer
中的代码如下:
public void InitializeDatabase(MyContext context)
{
//delete any existing database, and re-create
context.Database.Delete();
context.Database.Create();
//apply all migrations
var dbMigrator = new DbMigrator(new Configuration());
dbMigrator.Update();
//seed with data
this.Seed(context);
context.SaveChanges();
}
我的InitialCreate迁移的Up
方法没有被这段代码调用,这不是我所期望的。相反,所有表都是在调用Database.Create()
方法时创建的。我需要运行InitialCreate迁移,因为我有额外的代码来创建存储过程。
所以我的问题是,我如何以编程方式创建一个新数据库并运行所有迁移(包括InitialCreate迁移)?
下面的代码使我能够满足问题中概述的集成测试场景的需要,但是肯定有更好的方法吗?
public void InitializeDatabase(MyContext context)
{
//delete any existing database, and re-create
context.Database.Delete();
var newDbConnString = context.Database.Connection.ConnectionString;
var connStringBuilder = new SqlConnectionStringBuilder(newDbConnString);
var newDbName = connStringBuilder.InitialCatalog;
connStringBuilder.InitialCatalog = "master";
//create the new DB
using(var sqlConn = new SqlConnection(connStringBuilder.ToString()))
{
using (var createDbCmd = sqlConn.CreateCommand())
{
createDbCmd.CommandText = "CREATE DATABASE " + newDbName;
sqlConn.Open();
createDbCmd.ExecuteNonQuery();
}
}
//wait up to 30s for the new DB to be fully created
//this takes about 4s on my desktop
var attempts = 0;
var dbOnline = false;
while (attempts < 30 && !dbOnline)
{
if (IsDatabaseOnline(newDbConnString))
{
dbOnline = true;
}
else
{
attempts++;
Thread.Sleep(1000);
}
}
if (!dbOnline)
throw new ApplicationException(string.Format("Waited too long for the newly created database '"{0}'" to come online", newDbName));
//apply all migrations
var dbMigrator = new DbMigrator(new Configuration());
dbMigrator.Update();
//seed with data
this.Seed(context);
context.SaveChanges();
}
private bool IsDatabaseOnline(string connString)
{
try
{
using (var sqlConn = new SqlConnection(connString))
{
sqlConn.Open();
return sqlConn.State == ConnectionState.Open;
}
}
catch (SqlException)
{
return false;
}
}
只需删除"创建数据库"步骤,并自行使用迁移。我在GitHub上放了一个示例项目,但重要的是
Configuration config = new Configuration();
DbMigrator migrator = new DbMigrator(config);
foreach (string s in migrator.GetPendingMigrations())
{
migrator.Update(s);
}