如何在不使用update-database的情况下生成启用迁移的EF6数据库?

时间:2013-10-21 00:39:30

标签: entity-framework

在EF5中,我依赖的事实是我可以使用Database.CreateIfNotExists()

从模型中重新创建我的数据库

我会根据需要生成迁移,但永远不会将它们检入源代码控制(因为它们往往是开发周期的工件)然后每个开发人员都会根据需要从模型中删除并重新创建自己的数据库。

然后,我们将通过比较代码的分支并获取SQL来生成迁移,以应用于生产或其他共享数据库。

此工作流似乎不再起作用,因为在启用迁移时无法从头开始生成数据库,而无需先生成所有迁移,然后再调用update-database。由于调用add-migration会修改csproj文件,这使得我的脚本(允许我们轻松切换分支)无法使用。

  

为上下文“ApplicationDbContext”启用了迁移,但数据库不存在或不包含映射表。使用迁移创建数据库及其表,例如通过从程序包管理器控制台运行“Update-Database”命令。

有没有办法恢复到EF5行为,其中Database.Create将创建当前版本的db?

4 个答案:

答案 0 :(得分:12)

我正在使用CreateDatabaseIfNotExists初始化数据库,并且能够使用update-database并运行我的应用程序,如果数据库尚不存在,它将创建数据库。这似乎与EF 6.0.x有关。

This was useful, but not what I used.

我所做的是放弃我现有的初始化代码,并将其替换为Global.asax中的以下代码。

Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, Configuration>());
        using (MyContext temp = new MyContext())
        {
            temp.Database.Initialize(true);
        }

注意:MyContext是我使用的上下文,Configuration是启用迁移时创建的配置文件。

我见过很多帖子,人们对此有疑问,但描述解决方案的人并不多。我不确定为什么这么多人,包括我自己,都错过了这个突破性的变化......(如果有某个地方的描述,我从来没有见过它,直到为时已晚。)

编辑:

这是我添加到上下文类的代码。我不喜欢它曾经如何工作,但它现在完成了工作。请参阅@ Doug对OP关于CodePlex投票的评论。

private static readonly Object syncObj = new Object();
public static bool InitializeDatabase()
{
    lock (syncObj)
    {
        using (var temp = new TbdContext())
        {
            ObjectContext oc = null;
            try
            {
                oc = temp.ObjectContext;
            }
            catch (Exception ex)
            {
                //Ignore error
                Console.WriteLine(ex);
            }

            if (oc != null && oc.DatabaseExists())
            {
                return true;
            }
            Database.SetInitializer(new MigrateDatabaseToLatestVersion<TbdContext, Configuration>());
            try
            {
                temp.Database.Initialize(true);
                return true;
            }
            catch (DataException ex)
            {

        }
    }
}

然后在我的Global.asax.cs Application_Start()中执行此操作:

if (databaseInitialized == false)
    databaseInitialized = MyContext.InitializeDatabase();

编辑:

我已升级到EF 6.1并发现此功能不再有效。(https://stackoverflow.com/a/22770517/2033294)以下是我要解决的问题:

    private static readonly Object syncObj = new Object();
    public static bool InitializeDatabase()
    {
        lock (syncObj)
        {
            using (var temp = new MyContext())
            {
                if (temp.Database.Exists()) return true;

                var initializer = new MigrateDatabaseToLatestVersion<MyContext, Configuration>();
                Database.SetInitializer(initializer);
                try
                {
                    temp.Database.Initialize(true);
                    return true;
                }
                catch (Exception ex)
                {
                    //Handle Error in some way
                    return false;
                }
            }
        }
    }

答案 1 :(得分:2)

这对我有用(到目前为止......):

var connectionString = "Data Source=localhost;Initial Catalog=Chilli;" + 
    "Integrated Security=True;" + 
    "MultipleActiveResultSets=True;Application Name=ChilliDesktop";

//ooops... you have to create a new, blank database if one does not exist
var bld = new SqlConnectionStringBuilder(connectionString);
var dbName = bld.InitialCatalog; //i.e. Chilli

bld.InitialCatalog = "master";

//a connectionstring pointing at Master
var masterConnectionString = bld.ConnectionString; 

using (var cnn = new SqlConnection(masterConnectionString))
{
  var cmdString = string.Format(
     "if not exists (select * from sys.databases where name='{0}')" + 
     "\r\ncreate database {0}",
     dbName);
   using (var cmd = new System.Data.SqlClient.SqlCommand(cmdString,cnn))
   {
     cmd.Connection.Open();
     cmd.ExecuteNonQuery();
   }                
 }


var connectionInfo = 
    new System.Data.Entity.Infrastructure
        .DbConnectionInfo(connectionString, "System.Data.SqlClient");
//new up your auto-created Migrations Configuration class
var config = new Chilli.Context.Migrations.Configuration();
config.TargetDatabase = connectionInfo;
//new up a Migrator
var migrator = new System.Data.Entity.Migrations
    .DbMigrator(config);
migrator.Update();
//you now have a database

//run your Seed method
using (var dc = new Chilli.Context.Context(connectionString))
{
    Chilli.Context.ChilliContextInitializerHelper.Seed(dc);
}

http://softwaremechanik.wordpress.com/2013/11/04/ef6-if-migrations-are-enabled-cannot-createdatabaseifnotexists/

答案 2 :(得分:2)

这是答案......

EF团队分流:这是'设计',是我们在EF6中进行的有意改变。如果使用此初始化程序创建数据库,则会在__MigrationsHistory表中添加单个条目,然后使用迁移使数据库无法使用(因为这些初始化程序不使用迁移来创建数据库)。这使以前版本中的大量人员感到困惑,因此我们选择在启用迁移时不自动创建数据库/模式。

如果您只想应用迁移,可以使用MigrateDatabaseToLatestVersion初始值设定项。如果要删除数据库,则可以轻松地将其包装在包含对context.Database.Delete()的调用的自定义初始化程序中。

http://entityframework.codeplex.com/workitem/1689

答案 3 :(得分:1)

让其他人陷入困境。我最终在EF6中这样做了。

public CatContext(bool forcePreparation)
{
    if (!forcePreparation)
        return;

    if (!Database.Exists() || !Database.CompatibleWithModel(false))
    {
        Database.SetInitializer<CatContext>(new MigrateDatabaseToLatestVersion<CatContext, Configuration>());
    }
    else
    {
        // Database exists and matches the current model.
        // Doing this special thing to avoid the bug that arises sometimes.
        Database.SetInitializer<CatContext>(null);
    }

    Database.Initialize(true);
}

public CatContext()
    : this(forcePreparation: false)
{ }

在我的代码中,我将上下文对象创建为new CatContext(true)