Dr Rob Lang
Dr Rob Lang

Reputation: 6883

Insert InitialCreate migration into database without performing the schema changes

I am adding Code First migrations to an existing Entity Framework 6 domain with existing databases. I need the following behaviour:

  1. If the database exists, insert the InitialCreate migration but do not perform the contents of the migration Up().
  2. If the database does not exist, create it and run the contents of Up() and Down() to create an empty but correct-schema database.

I need (1) for when I release through the Continuous Delivery deployment. I need (2) for when a developer is cleaning down their machine and starting fresh. I do not want to use automatic migrations.

I appreciate that a Migration has no concept of the Database Context, it's only responsible for generating a series of SQL instructions.

Are these my only options?

1. Move contents of Up and Down out of InitialCreate and into Configuration.Seed

The InitialCreate migration runs Up() but no changes are made. In Seed() we have access to DbContext, so we can work out if the tables exist and create them if needed.

I think this might break when there are lots of migrations to run as Seed() is called after the migrations. On an empty database, the creation of the tables would be happening after updates to those schemas.

2. Perform the Up() method as a SQL Script

Migrations allows the developer to put inline SQL into Up() and Down(). Move the creation of the database into inline SQL and add a IF NOT EXISTS at the top.

I don't like this because you lose the use of the model that is supplied with the InitialCreate. If the model is updated, the fixed SQL string won't.

3. Empty out the Up() and Down() methods, do a release, put the creation code back in, do another release

When the InitialCreate migration is run first time, it won't have anything in it. The entry will go into the migrations database without running anything.

Once that first release has been performed, I can then put the creation code back in so that when future developers run it without a database, it will create properly.

Note: This one is my current favourite as it uses Entity Framework as designed and I can personally control adding the code back in after a release.

Is there a better way?

Edit

I am unable to build the database from empty, this might be something to do with the Context model creation. It uses a bespoke pluggable method:

    public MyObjectContext()
    {
        ((IObjectContextAdapter) this).ObjectContext.ContextOptions.LazyLoadingEnabled = true;
        ((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 180;
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        System.Type configType = typeof(AnswerMap);   //any of your configuration classes here
        var typesToRegister = Assembly.GetAssembly(configType).GetTypes()
        .Where(type => !String.IsNullOrEmpty(type.Namespace))
        .Where(type => type.BaseType != null && type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
        foreach (var type in typesToRegister)
        {
            dynamic configurationInstance = Activator.CreateInstance(type);
            modelBuilder.Configurations.Add(configurationInstance);
        }
        base.OnModelCreating(modelBuilder);
    }

All the map objects are in the same DLL, the domain entities used for the database tables are in a separate DLL.

Upvotes: 1

Views: 449

Answers (1)

Steve Greene
Steve Greene

Reputation: 12304

This is what we do:

1) Create an initial migration that is a snapshot of the current database. Use -IgnoreChanges to keep any code out of the Up(). You don't need the Up() code because EF will compare the prior model (blank) to the one stored in the migration and realize you need to add all the existing objects at the time of the snapshot.

add-migration Initial -IgnoreChanges

2) Add new migrations as you develop. In a team environment you could run into the issues outlined here: https://msdn.microsoft.com/en-US/data/dn481501

3) You can generate an idempotent script that will rebuild an entire system from scratch and apply any (or all) migrations.

Update-Database -Script -SourceMigration $InitialDatabase

https://msdn.microsoft.com/en-us/data/jj591621.aspx?f=255&MSPPError=-2147217396#idempotent

Upvotes: 2

Related Questions