20

I am using Entity Framework Code First approach with AutomaticMigrationsEnabled = true:

Database.SetInitializer(new MigrateDatabaseToLatestVersion<DbContext, MigrateDBConfiguration>());
//////////////////////////////////

public class MigrateDBConfiguration : System.Data.Entity.Migrations.DbMigrationsConfiguration<DbContext>
{
    public MigrateDBConfiguration()
    {
        AutomaticMigrationsEnabled = true;
        AutomaticMigrationDataLossAllowed = true;
    }
}

The first run of the project creates the database and tables as expected. After changing my model by adding or dropping fields, I ran Add-Migration. The Migration class was generated but after running the project this exception occurs:

An exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll but was not handled in user code

Additional information: The model backing the 'DBContext' context has changed since the database was created.

EDIT: Per the guidance in the answer of arturo menchaca I changed my code like this:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        Database.SetInitializer(new MigrateDatabaseToLatestVersion<DBContext, MigrateDBConfiguration<DBContext>>());

...

After the change this exception is occurring:

There is already an object named 'MyTable' in the database.

How can I apply my database migration?

Fred
  • 3,365
  • 4
  • 36
  • 57
  • One thing to check is to see if you have changed your namespaces at all. Entity Framework migrations are very sensitive to namespacing as that seems to be where a lot of the voodoo seems to happen with migrations. I was burned in the past by a adjusting namespaces to fit the folder structure that migrations creates by default. – kmacdonald Mar 28 '16 at 16:16
  • it sounds like you are combining automatic migrations with manual migations. This can cause some serious migrationHistory issues in the database (at least as far as i have experienced). If you are generating manual migrations try turning off automatic migrations. – kmacdonald Mar 28 '16 at 16:26

5 Answers5

22

Automatic Migrations means that you don't need to run add-migration command for your changes in the models, but you have to run update-database command manually.

If Automatic Migrations is enabled when you call update-database, if there are pending changes in your models, an 'automatic' migration will be added and database will be updated.

If you want that your database is updated without need to call update-database command, you can add Database.SetInitializer(...) in OnModelCreating() method on your context, like so:

public class MyContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, MigrateDBConfiguration>());
    }

    ...
}

public class MigrateDBConfiguration : System.Data.Entity.Migrations.DbMigrationsConfiguration<MyContext>
{
    ...

Note that you should declare DbMigrationsConfiguration and MigrateDatabaseToLatestVersion with your real context, not the default DbContext.

Arturo Menchaca
  • 15,783
  • 1
  • 29
  • 53
  • 3
    this is actually not true. By using the MigrateToTheLatestMigrationVersion database intializer this should work (it has worked in the past for me). I am actually having this same issue right now. I am not sure what i changed but i know this setup has worked in the past. – kmacdonald Mar 28 '16 at 16:15
  • I want that my database is updated without need to call update-database and try your solution and not work. – Fred Mar 28 '16 at 16:44
  • @Fred: In your code you have declared `MigrateDBConfiguration` as `DbMigrationsConfiguration`, `DbContext` is the name of you context?, if that is the case, be aware of not to confuse it with `System.Data.Entity.DbContext` – Arturo Menchaca Mar 28 '16 at 16:53
  • @ArturoMenchaca my DbContext class name is DbAccess, in above question write DbContext to simplicity. – Fred Mar 28 '16 at 17:01
  • @Fred: And `Database.SetInitializer(...` is called in `OnModelCreating` or `DbAccess` constructor? – Arturo Menchaca Mar 28 '16 at 17:10
  • @ArturoMenchaca Database.SetInitializer(... called in OnModelCreating like last edit my question – Fred Mar 28 '16 at 17:19
  • seems like your applied migrations to database and _MigrationHistory table values are not synchronized, can you drop your tables including _MigrationHistory (if not at least delete MyTable) and try it again? – Arturo Menchaca Mar 28 '16 at 17:29
  • @ArturoMenchaca yes it work.but I want to apply my explicit generated migration in future and I can not delete MyTable per each migration – Fred Mar 28 '16 at 17:36
  • @Fred: This should not happens again, but note that drops operations cant be done with automatic migrations, but code-based migrations. If you add a set using automatic migration, then just remove it from the context and run the program, then add it back with an code-based migration this kind of error will happens, you should be aware when combine automatic with code-based migrations. – Arturo Menchaca Mar 28 '16 at 18:10
21

Finally, I found a solution to my problem. I call this method in each application start :

public void InitializeDatabase(DataAccessManager context)
{
    if (!context.Database.Exists() || !context.Database.CompatibleWithModel(false))
    {
        var configuration = new DbMigrationsConfiguration();
        var migrator = new DbMigrator(configuration);
        migrator.Configuration.TargetDatabase = new DbConnectionInfo(context.Database.Connection.ConnectionString, "System.Data.SqlClient");
        var migrations = migrator.GetPendingMigrations();
        if (migrations.Any())
        {
            var scriptor = new MigratorScriptingDecorator(migrator);
            var script = scriptor.ScriptUpdate(null, migrations.Last());

            if (!string.IsNullOrEmpty(script))
            {
                context.Database.ExecuteSqlCommand(script);
            }
        }
    }
}
Fred
  • 3,365
  • 4
  • 36
  • 57
6

If you have change in your entities, you need first run add-migration to create the migration script.

After that in your Global.asax

you need to have some code like this

        var configuration = new MyProject.Configuration();
        var migrator = new System.Data.Entity.Migrations.DbMigrator(configuration);            

        migrator.Update();

every time that you run your asp.net project it'll check if you have a new migration to run and run update-database automatically for you.

gorums
  • 1,567
  • 13
  • 5
2

Microsoft addresses migrations at runtime, here.

For example, you can do this in Program.cs: (tested working in .NET 5.0 preview)

public static void Main(string[] args)
{
    var host = CreateHostBuilder(args).Build();

    MigrateDatabase(host);

    host.Run();
}

private static void MigrateDatabase(IHost host)
{
    using var scope = host.Services.CreateScope();
    var services = scope.ServiceProvider;

    try
    {
        var context = services.GetRequiredService<ApplicationDbContext>();
        context.Database.Migrate();
    }
    catch (Exception ex)
    {
        var logger = services.GetRequiredService<ILogger<Program>>();
        logger.LogError(ex, "An error occurred creating the DB.");
    }
}
Jack Miller
  • 6,843
  • 3
  • 48
  • 66
TimB
  • 493
  • 3
  • 16
0

using Microsoft.EntityFrameworkCore;

        await _dbContext.Database.MigrateAsync();
        _dbContext.Database.Migrate();

OR

        await _dbContext.Database.EnsureCreatedAsync();
         _dbContext.Database.EnsureCreated();

both method check if database exist, if not they both create it.

  • Migrate() uses migrations and is suitable if you use migrations or relational database.
  • EnsureCreated() does not use migrations which means once db is created using this method no further migrations can be executed over it.
BNG016
  • 164
  • 1
  • 7