Mysql
 sql >> Base de données >  >> RDS >> Mysql

Comment créer un initialiseur pour créer et migrer une base de données mysql ?

Je pense que vous y êtes à peu près - vous pouvez rechercher le code source pour MigrateDatabaseToLatestVersion (c'est open source http://entityframework.codeplex.com/ ) - c'est assez simpliste, ce qu'il fait à peu près, c'est appeler le DbMigrator - aussi loin que je pouvais voir.

Tout ce que vous avez à faire semble être de fusionner les deux - utilisez l'un ou l'autre comme base, ajoutez d'autres fonctionnalités là-dedans - cela devrait bien fonctionner, je pense.

class CreateAndMigrateDatabaseInitializer<TContext, TConfiguration> : CreateDatabaseIfNotExists<TContext>, IDatabaseInitializer<TContext> 
    where TContext : DbContext
    where TConfiguration : DbMigrationsConfiguration<TContext>, new()
{
    private readonly DbMigrationsConfiguration _configuration;
    public CreateAndMigrateDatabaseInitializer()
    {
        _configuration = new TConfiguration();
    }
    public CreateAndMigrateDatabaseInitializer(string connection)
    {
        Contract.Requires(!string.IsNullOrEmpty(connection), "connection");

        _configuration = new TConfiguration
        {
            TargetDatabase = new DbConnectionInfo(connection)
        };
    }
    void IDatabaseInitializer<TContext>.InitializeDatabase(TContext context)
    {
        Contract.Requires(context != null, "context");

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

        // move on with the 'CreateDatabaseIfNotExists' for the 'Seed'
        base.InitializeDatabase(context);
    }
    protected override void Seed(TContext context)
    {
    }
}

appelez-le comme ça...

Database.SetInitializer(new CreateAndMigrateDatabaseInitializer<GumpDatabase, YourNamespace.Migrations.Configuration>());

... en fait, remplacez-le (puisqu'il s'agit d'une implémentation générique) comme vous le faisiez pour CreateDatabaseIfNotExists (vous avez juste un "param" supplémentaire pour la configuration) - et fournissez simplement la "graine".

class GumpDatabaseInitializer : CreateAndMigrateDatabaseInitializer<GumpDatabase, YourNamespace.Migrations.Configuration>
{
    protected override void Seed(GumpDatabase context)
    {
        context.Database.ExecuteSqlCommand("CREATE UNIQUE INDEX Name ON Stations (Name)");
    }
}

...et appelez-le quelque chose comme

Database.SetInitializer(new GumpDatabaseInitializer());

MODIF : D'après les commentaires - DbMigrator ne devrait pas s'exécuter deux fois. Il vérifie toujours (passe un peu de temps) et fait une mise à jour "vierge" et passe à autre chose. Cependant, juste au cas où vous voudriez supprimer cela et "vérifier" avant d'entrer - cela devrait fonctionner (changez la pièce similaire ci-dessus)...

var migrator = new DbMigrator(_configuration);
if (!context.Database.CompatibleWithModel(throwIfNoMetadata: false))
    if (migrator.GetPendingMigrations().Any())
        migrator.Update();

(il s'agit d'une redondance / double vérification - l'un des if-s devrait suffire. Faites une pause ici - et voyez exactement ce qui se passe, cela ne devrait pas entrer - une fois que Db est migré. Comme je l'ai mentionné, fonctionne bien quand je testez-le.

MODIF :

Remplacez l'intérieur de InitializeDatabase avec...

var doseed = !context.Database.Exists();
// && new DatabaseTableChecker().AnyModelTableExists(context);
// check to see if to seed - we 'lack' the 'AnyModelTableExists' - could be copied/done otherwise if needed...

var migrator = new DbMigrator(_configuration);
// if (doseed || !context.Database.CompatibleWithModel(throwIfNoMetadata: false))
    if (migrator.GetPendingMigrations().Any())
        migrator.Update();

// move on with the 'CreateDatabaseIfNotExists' for the 'Seed'
base.InitializeDatabase(context);
if (doseed)
{
    Seed(context);
    context.SaveChanges();
}

Cela fonctionne autour du non-ensemencement (à mi-chemin) - si la migration commence en premier. Et les migrations doivent être les premières, sinon vous avez des problèmes.

Vous devez toujours le faire correctement - c'est l'essentiel sinon tout ce dont vous pourriez avoir besoin - mais en cas de problème avec MySQL, etc., probablement un peu plus de travail ici.

Remarque : L'ensemencement n'appelle toujours pas si vous avez une base de données, mais elle est vide. Le problème est le mélange des deux initialiseurs différents. Vous devrez donc résoudre ce problème - soit en implémentant ce que Create... fait à l'intérieur (cet appel que nous ne pouvons pas appeler) ou autre chose.