Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I generate an EF6 database with migrations enabled, without using update-database?

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?

like image 933
Doug Avatar asked Oct 21 '13 00:10

Doug


People also ask

How do I code my first migration to an existing database?

Run the Add-Migration InitialCreate command in Package Manager Console. This creates a migration to create the existing schema. Comment out all code in the Up method of the newly created migration. This will allow us to 'apply' the migration to the local database without trying to recreate all the tables etc.

Which command generates a SQL script from migrations?

With From and To The following generates a SQL script from the specified from migration to the specified to migration. You can use a from that is newer than the to in order to generate a rollback script.

How do I create a database Migrate?

Creating Migrations To create a migration, execute db-migrate create with a title. node-db-migrate will create a node module within ./migrations/ which contains the following two exports: exports. up = function (db, callback) { callback(); }; exports.

Which of the following is the correct migration command to create models from the existing database?

You use the DbContext Scaffold command to generate the model. The command has two required arguments - a connection string and a provider. The connection string will depend on your environment and database provider.


2 Answers

I was using CreateDatabaseIfNotExists to initialize the DB and was able to use update-database and run my application and it would create the DB if it didn't already exist. This seems to have broken with EF 6.0.x.

This was useful, but not what I used.

What I did was abandon my existing initialize code and replaced it with the following code in Global.asax.

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

Note: MyContext is the context I use and Configuration is the Configuration file that is created when migrations are enabled.

I have seen a lot of posts where people are having problems about this, but not many that describe a solution. I'm not sure why so many people, including myself, have missed this breaking change... (If there's a description about this somewhere, I never saw it until it was too late.)

Edit:

This is code that I added to my context class. I don't like it as much as how it used to work, but it gets the job done for now. See @Doug's comment to the OP about voting on 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)
            {

        }
    }
}

Then in my Global.asax.cs Application_Start() I do this:

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

Edit:

I upgraded to EF 6.1 and found this doesn't work anymore.(https://stackoverflow.com/a/22770517/2033294) Here's what I did to fix it:

    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;
                }
            }
        }
    }
like image 105
Jeff Avatar answered Oct 08 '22 11:10

Jeff


This works for me (so far...):

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/

like image 38
ajd Avatar answered Oct 08 '22 12:10

ajd