问题描述
我正在使用Entity Framework Code First迁移,并且在一种情况下,我想运行一套集成测试。每次运行测试时,我都想重新创建数据库并应用所有迁移
I'm using Entity Framework Code First migrations, and I have a scenario where I want to run a suite of integration tests. Each time the tests run, I want to re-create the database, and apply all migrations
步骤应为:
- 拖放现有的测试数据库(如果有)
- 创建一个新的测试数据库,并应用所有迁移
- 种子数据
这是一个现有项目,我向其中添加了迁移,并使用Enable-Migrations命令创建
This is an existing project that I've added migrations to, and I used the Enable-Migrations command to create an "InitialCreate" migration that contains code to add all the tables to my database.
自定义 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();
}
Up
方法此代码未调用InitialCreate迁移的一部分,这不是我期望的。而是在调用 Database.Create()
方法时创建所有表。我需要运行InitialCreate迁移,因为其中还有其他代码可以创建存储过程。
The Up
method of my InitialCreate migration is not getting called by this code, which is not what I expected. Instead, all of the tables are created when the Database.Create()
method is called. I need the InitialCreate migration to run because I have additional code in there to create stored procedures.
所以我的问题是,如何以编程方式创建新数据库并运行所有数据库迁移(包括InitialCreate迁移)?
So my questions is, how do I programmatically create a new database and run all migrations (including the InitialCreate migration)?
推荐答案
以下代码使我能够满足概述中所述的集成测试方案的需求这个问题,但是肯定有更好的方法吗?
The following code has allowed me to meet the needs of my integration testing scenario outlined in the question, but surely there's a better way?
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;
}
}
这篇关于EF 5,代码优先-创建新数据库并以编程方式运行所有迁移的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!