Search code examples
c#entity-frameworkdatabase-migrationautomatic-migration

How to enable automatic migration when using custom DB initializer c#


I have created a custom database initializer so that I can override the seed method and add data to the database each time it is created using the DropCreateDatabaseIfModelChanges initializer. See code below:

public class BehaviourContext : DbContext
{
    public BehaviourContext(): base("name=BehaviourDBConnectionString")
    {
        Database.SetInitializer<BehaviourContext>(new BehaviourInitializer<BehaviourContext>());
    }
    public DbSet<Behaviour> Behaviours { get; set; }
    public DbSet<Precondition> Preconditions { get; set; }
    public DbSet<AddList> AddLists { get; set; }
    public DbSet<DeleteList> DeleteLists { get; set; }
    public DbSet<AtomicBehaviour> AtomicBehaviours { get; set; }

}

public class BehaviourInitializer<T> : DropCreateDatabaseIfModelChanges<BehaviourContext>
{
    protected override void Seed(BehaviourContext context)
    {
        //Add Seed data for the database
        IList<Behaviour> defaultBehaviours = new List<Behaviour>();

        defaultBehaviours.Add(new Behaviour()
        {
            Activation_Threshold = 90,
            Currently_Executing = false,
            Name = "Test Behaviour",
            Preconditions_Met = false,
            Priority = 0.9f,
            Preconditions = new List<Precondition>() { new Precondition() { Precondition_Name = "test precondition 1", Value = "test value 1" }, new Precondition() { Precondition_Name = "test precondition 2", Value = "test value 2" } },
            AddLists = new List<AddList>() { new AddList() { Name = "test add list 1" }, new AddList() {  Name = "test add list 2"} },
            DeleteList = new List<DeleteList>() { new DeleteList() { Name = "test delete list 1" }, new DeleteList() { Name = "test delete list 2"} },
            AtomicList = new List<AtomicBehaviour>() { new AtomicBehaviour() { Name = "test atomic behaviour 1" }, new AtomicBehaviour(){Name = "test atomic behaviour 2"}}
        });

        base.Seed(context);
    }
}

So my question is how to enable automatic migration with a custom initializer? The code below shows my attempt to do this:

public class BehaviourContext : DbContext
{
    public BehaviourContext(): base("name=BehaviourDBConnectionString")
    {
        Database.SetInitializer<BehaviourContext>(new BehaviourInitializer<BehaviourContext>());
        //Database.SetInitializer<BehaviourContext>(new MigrateDatabaseToLatestVersion<BehaviourContext, System_Architecture.Migrations.Configuration>("name=BehaviourDBConnectionString"));
    }
    public DbSet<Behaviour> Behaviours { get; set; }
    public DbSet<Precondition> Preconditions { get; set; }
    public DbSet<AddList> AddLists { get; set; }
    public DbSet<DeleteList> DeleteLists { get; set; }
    public DbSet<AtomicBehaviour> AtomicBehaviours { get; set; }

}

public class BehaviourInitializer<T> : MigrateDatabaseToLatestVersion<BehaviourContext,System_Architecture.Migrations.Configuration>
{
    protected override void Seed(BehaviourContext context)
    {
        //Add Seed data for the database
        IList<Behaviour> defaultBehaviours = new List<Behaviour>();

        defaultBehaviours.Add(new Behaviour()
        {
            Activation_Threshold = 90,
            Currently_Executing = false,
            Name = "Test Behaviour",
            Preconditions_Met = false,
            Priority = 0.9f,
            Preconditions = new List<Precondition>() { new Precondition() { Precondition_Name = "test precondition 1", Value = "test value 1" }, new Precondition() { Precondition_Name = "test precondition 2", Value = "test value 2" } },
            AddLists = new List<AddList>() { new AddList() { Name = "test add list 1" }, new AddList() {  Name = "test add list 2"} },
            DeleteList = new List<DeleteList>() { new DeleteList() { Name = "test delete list 1" }, new DeleteList() { Name = "test delete list 2"} },
            AtomicList = new List<AtomicBehaviour>() { new AtomicBehaviour() { Name = "test atomic behaviour 1" }, new AtomicBehaviour(){Name = "test atomic behaviour 2"}}
        });

        base.Seed(context);
    }
}

The commented out line of code in the BehaviourConext class is how one would enable automatic migration normally however I do not know how to do this with my custom initializer and I now receive the error shown when I try to inherit from MigrateDatabaseToLatestVersion.

Does anyone have any ideas?

Note: I have enabled automatic migrations in the package manager.


Solution

  • The reason you are getting that specific error is because in your Configuration.cs file in the Migration folder (that gets created after running Enable-Migrations in PM Console) is set to internal sealed. Therefore, it can't be inherited as sealed classes are by definition not inheritable.

    I would recommend actually moving your seed method into your Configuration.cs file and use Update-Database through PM to generate your database. This is more inline with normal EF practices.

    Then, if you'd like to enable automatic migrations, add the line AutomaticMigrationsEnabled = true; to your Configuration initializer.