MigrateDatabaseToLatestVersion no running Seed() m

2020-06-13 16:59发布

问题:

I'm trying to automatically generate my database if it doesn't exists and run the Seed() method to populate the data. In my Database Context constructor I have this:

Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDBContext, Configuration>());

This works great, my database is automatically created with all the tables as I want, but it seems like the Seed() method is not being called, my database is empty. This is my class:

internal sealed class Configuration : DbMigrationsConfiguration<Context.MyDBContext>
{

    public Configuration()
    {
        AutomaticMigrationsEnabled = true;
    }

    protected override void Seed(Context.MyDBContext context)
    {
        context.Users.AddOrUpdate(
            new Entities.User() { Email = "default@default.com", Password = "", Language = "en", CreatedDate = DateTime.Now }
        );

        base.Seed(context);
    }
}

When I run Update-Database in the Nuget console the data is populated after database creation, but with MigrateDatabaseToLatestVersion the Seed() method is not called.

What can be happening? I tried manually running migrations as taken from here:

var configuration = new MyDbContextConfiguration();
configuration.TargetDatabase = new DbConnectionInfo(
    database.ConnectionString, database.ProviderName);

var migrator = new DbMigrator(configuration);
migrator.Update();

But also doesn't work.


EDIT:

Ok, after some more testing I found that the Seed() method runs but only when the database already exists, that is, on the first run when the database is created for the first time the Seed() method is not executed, but when I run my app the second time Seed() get's executed. I also had to add context.SaveChanges() in order for it to work (thanks to @DavidG in the comments):

protected override void Seed(Context.MyDBContext context)
    {
        context.Users.AddOrUpdate(
            new Entities.User() { Email = "default@default.com", Password = "", Language = "en", CreatedDate = DateTime.Now }
        );

        context.SaveChanges();
        base.Seed(context);
    }

So maybe I can manually call Seed() inside Configuration() and do some checking to avoid adding duplicating data or modifying data that already exists.

回答1:

I ended up with this Configuration class:

public class Configuration : DbMigrationsConfiguration<Context.MyDBContext>
    {
        private readonly bool _pendingMigrations;

        public Configuration()
        {
            AutomaticMigrationsEnabled = true;

            // Check if there are migrations pending to run, this can happen if database doesn't exists or if there was any
            //  change in the schema
            var migrator = new DbMigrator(this);
            _pendingMigrations = migrator.GetPendingMigrations().Any();

            // If there are pending migrations run migrator.Update() to create/update the database then run the Seed() method to populate
            //  the data if necessary
            if (_pendingMigrations)
            {
                migrator.Update();
                Seed(new Context.MyDBContext());
            }
        }

        protected override void Seed(Context.MyDBContext context)
        {
            // Microsoft comment says "This method will be called after migrating to the latest version."
            // However my testing shows that it is called every time the software starts

            // Run whatever you like here

            // Apply changes to database
            context.SaveChanges();
            base.Seed(context);
        }
    }

So on this way the Seed() method is called when the database is created and also when there are pending migrations.

This is my MyDBContext class:

public class MyDBContext: DbContext
{
    public MyDBContext() : base(AppSettings.DBConnectionString)
    {
    }

    public static MyDBContext Create()
    {
        return new MyDBContext();
    }

    public DbSet<User> Users { get; set; }
    public DbSet<Entries> Entries { get; set; }
}