如何创建初始化程序来创建和迁移mysql数据库?

Mat*_*att 14 c# mysql migration initializer entity-framework-4.3

我一直在学习如何使用EF一个星期左右,我一直坚持创建/更新我的数据库的问题.如果不存在,我可以创建一个初始化器来创建数据库:

static class Program
{
    static void Main()
    {
        Database.SetInitializer<GumpDatabase>(new GumpDatabaseInitializer());
....

class GumpDatabaseInitializer : CreateDatabaseIfNotExists<GumpDatabase>
{
    public GumpDatabaseInitializer()
    {
    }
    protected override void Seed(GumpDatabase context)
    {
        context.Database.ExecuteSqlCommand("CREATE UNIQUE INDEX Name ON Stations (Name)");
        // Other stuff
    }
}
Run Code Online (Sandbox Code Playgroud)

或者我可以创建配置来迁移数据库

static class Program
{
    static void Main()
    {
        Database.SetInitializer<GumpDatabase>(new MigrateDatabaseToLatestVersion<GumpDatabase, Configuration>());
....

internal sealed class Configuration : DbMigrationsConfiguration<GumpDatabase>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = true;
        SetSqlGenerator("MySql.Data.MySqlClient", new MySql.Data.Entity.MySqlMigrationSqlGenerator()); 
    }

    protected override void Seed(GumpDatabase context)
    {

    }
Run Code Online (Sandbox Code Playgroud)

每个都正常工作,但我还没有想出办法做到这两点.我可以通过更改SetInitializer调用在两个初始化程序之间切换,但是如果我想创建数据库,如果它不存在,并且如果它是我该怎么做的话还要迁移它?我需要创建自定义初始化程序吗?

谢谢

根据NSGaga答案编辑

class CreateOrMigrateDatabaseInitializer<TContext, TConfiguration> : CreateDatabaseIfNotExists<TContext>, IDatabaseInitializer<TContext>
    where TContext : DbContext
    where TConfiguration : DbMigrationsConfiguration<TContext>, new()
{
    private readonly DbMigrationsConfiguration _configuration;
    public CreateOrMigrateDatabaseInitializer()
    {
        _configuration = new TConfiguration();
    }
    public CreateOrMigrateDatabaseInitializer(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");

        if (context.Database.Exists())
        {
            if (!context.Database.CompatibleWithModel(throwIfNoMetadata: false))
            {
                var migrator = new DbMigrator(_configuration);
                migrator.Update();
            }
        }
        else
        {
            context.Database.Create();
            Seed(context);
            context.SaveChanges();
        }


    }
    protected virtual void Seed(TContext context)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

internal sealed class Configuration : DbMigrationsConfiguration<GumpDatabase>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = true;
        AutomaticMigrationDataLossAllowed = false;
        SetSqlGenerator("MySql.Data.MySqlClient", new MySql.Data.Entity.MySqlMigrationSqlGenerator()); 
    }

    protected override void Seed(GumpDatabase context)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

class GumpDatabaseInitializer : CreateOrMigrateDatabaseInitializer<GumpDatabase,Gump.Migrations.Configuration>
{
    public GumpDatabaseInitializer()
    {
    }
    protected override void Seed(GumpDatabase context)
    {
        context.Database.ExecuteSqlCommand("CREATE UNIQUE INDEX Name ON Stations (Name)");
        context.Database.ExecuteSqlCommand("CREATE UNIQUE INDEX Name ON Sequences (Name)");
        context.Database.ExecuteSqlCommand("CREATE UNIQUE INDEX StationPartNumber ON StationPartNumbers (StationId,PartNumberId)");
    }
}
Run Code Online (Sandbox Code Playgroud)

最后

static void Main()
{
    Database.SetInitializer<GumpDatabase>(new GumpDatabaseInitializer());
Run Code Online (Sandbox Code Playgroud)

NSG*_*aga 16

我认为你几乎就在那里 - 你可以查找MigrateDatabaseToLatestVersion(这是开源的http://entityframework.codeplex.com/)的源代码- 它非常简单,它的功能几乎就是调用DbMigrator- 尽我所能看到.

所有你需要做的似乎是合并两个 - 使用一个或另一个作为基础,在那里添加其他功能 - 这应该工作正常我认为.

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)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

这样叫它......

Database.SetInitializer(new CreateAndMigrateDatabaseInitializer<GumpDatabase, YourNamespace.Migrations.Configuration>());
Run Code Online (Sandbox Code Playgroud)

...实际上,覆盖它(因为它是通用实现)就像你正在做的那样CreateDatabaseIfNotExists(你只需要配置额外的'param') - 并且只提供'种子'.

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

......并称之为

Database.SetInitializer(new GumpDatabaseInitializer());
Run Code Online (Sandbox Code Playgroud)

编辑: 根据评论 - DbMigrator不应该运行两次.它总是检查(花费一点时间)并进行"空白"更新并继续前进.但是,如果你想在进入之前删除它并"检查" - 这应该有用(改变上面的类似部分)......

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

(这是一个冗余/双重检查 - 其中一个if-s应该足够了.在那里休息一下 - 看看究竟发生了什么,它不应该进入 - 一旦Db被迁移.正如我所提到的,我工作正常测试一下.

编辑:

更换内部InitializeDatabase...

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();
}
Run Code Online (Sandbox Code Playgroud)

如果迁移是第一次的话,这可以解决(中途)非播种的问题.迁移必须是第一个,否则你就会遇到问题.

你仍然需要正确地做到这一点 - 如果不是你可能需要的话,这就是要点 - 但如果有任何问题与MySQL等有关,可能还有一些更多的工作在这里.

注意:如果你有一个数据库,仍然没有调用播种,但它是空的.问题是混合两种不同的初始化器.因此,您必须通过实现内部的Create ...(我们无法调用的调用)或其他内容来解决这个问题.