12

In EF5, I relied on the fact that I could recreate my database from the model using Database.CreateIfNotExists()

I would generate Migrations as needed, but never check them in to source control (since they tended to be artifacts of the development cycle) Each developer would then delete and recreate their own databases, from the model as needed.

Then, we would generate migrations by comparing branches of our code, and get the SQL, to apply to production or other shared databases.

This workflow no longer seems to work, as there is no way to generate a database from scratch when migrations are enabled, without first generating all the migrations and then calling update-database. Since calling add-migration modifies the csproj file, this makes my scripts (which allow us to easily switch branches) unusable.

Migrations is enabled for context 'ApplicationDbContext' but the database does not exist or contains no mapped tables. Use Migrations to create the database and its tables, for example by running the 'Update-Database' command from the Package Manager Console.

Is there any way to revert to EF5 behavior where Database.Create will create the current version of the db?

4

4 回答 4

12

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

这很有用,但不是我用的。

我所做的是放弃我现有的初始化代码,并将其替换为 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;
                }
            }
        }
    }
于 2013-11-05T17:57:46.237 回答
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/

于 2013-11-04T03:15:19.307 回答
2

给别人卡住了。我最终在 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).

于 2014-09-17T16:56:57.013 回答
2

这是答案...

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

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

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

于 2014-02-10T19:22:08.367 回答