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 を使用して DB を初期化し、update-database を使用してアプリケーションを実行できました。DB がまだ存在しない場合は作成されます。これは EF 6.0.x で壊れたようです。

これは便利でしたが、私が使用したものではありませんでした。

私がしたことは、既存の初期化コードを放棄し、Global.asax の次のコードに置き換えたことです。

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

注: MyContext は私が使用するコンテキストで、Configuration は移行が有効になったときに作成される構成ファイルです。

これについて人々が問題を抱えている投稿をたくさん見てきましたが、解決策を説明しているものは多くありません. なぜ私を含めて多くの人がこの重大な変更を見逃したのかわかりません... (これについての説明がどこかにある場合、手遅れになるまで見たことがありませんでした.)

編集:

これは、コンテキスト クラスに追加したコードです。以前のようには好きではありませんが、今のところ仕事は完了しています。CodePlex への投票に関する @Doug の OP へのコメントを参照してください。

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

これが答えです...

EF チームのトリアージ: これは「設計による」ものであり、EF6 で意図的に行った変更です。この初期化子を使用してデータベースを作成すると、単一のエントリが __MigrationsHistory テーブルに追加され、データベースが移行で使用できなくなります (これらの初期化子は移行を使用してデータベースを作成しないため)。これは以前のリリースで多くの人を混乱させたので、移行が有効になっているときにデータベース/スキーマを自動的に作成しないことにしました。

移行を適用するだけの場合は、MigrateDatabaseToLatestVersion 初期化子を使用できます。データベースを削除したい場合は、context.Database.Delete() への呼び出しを含むカスタム初期化子で簡単にラップできます。

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

于 2014-02-10T19:22:08.367 に答える