C# 如何创建初始化器来创建和迁移mysql数据库?

C# 如何创建初始化器来创建和迁移mysql数据库?,c#,mysql,migration,entity-framework-4.3,initializer,C#,Mysql,Migration,Entity Framework 4.3,Initializer,我已经学习如何使用EF一个星期左右了,我被困在创建/更新数据库的问题上。如果数据库不存在,我可以创建一个初始值设定项来创建数据库: static class Program { static void Main() { Database.SetInitializer<GumpDatabase>(new GumpDatabaseInitializer()); .... class GumpDatabaseInitializer : CreateData

我已经学习如何使用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
    }
}
静态类程序
{
静态void Main()
{
SetInitializer(新的GumpDatabaseInitializer());
....
类GumpDatabaseInitializer:CreateDatabaseIfNotExists
{
公共GumpDatabaseInitializer()
{
}
受保护的覆盖无效种子(GumpDatabase上下文)
{
context.Database.ExecuteSqlCommand(“在站点上创建唯一的索引名(名称)”);
//其他东西
}
}
或者我可以创建一个配置来迁移数据库

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)
    {

    }
静态类程序
{
静态void Main()
{
SetInitializer(新的MigrateDatabaseToLatestVersion());
....
内部密封类配置:DBMigOptionsConfiguration
{
公共配置()
{
AutomaticMiggerationsEnabled=真;
SetSqlGenerator(“MySql.Data.MySqlClient”,新的MySql.Data.Entity.MySqlMigrationSqlGenerator());
}
受保护的覆盖无效种子(GumpDatabase上下文)
{
}
每个都可以正常工作,但我还没有找到一种方法来同时执行这两个操作。我可以通过更改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)
    {
    }
}
class CreateDatabaseInitializer:CreateDatabaseIfNotExists,IDatabaseInitializer
其中TContext:DbContext
其中TConfiguration:DbMigrationsConfiguration,new()
{
专用只读DbMigrationsConfiguration\u配置;
公共CreateOrmigratedDatabaseInitializer()
{
_配置=新的TConfiguration();
}
公共CreateDatabaseInitializer(字符串连接)
{
Contract.Requires(!string.IsNullOrEmpty(connection),“connection”);
_配置=新的t配置
{
TargetDatabase=新的DbConnectionInfo(连接)
};
}
void IDatabaseInitializer.InitializeDatabase(TContext上下文)
{
Contract.Requires(context!=null,“context”);
if(context.Database.Exists())
{
if(!context.Database.CompatibleWithModel(throwifNMetadata:false))
{
var migrator=新的DbMigrator(_配置);
migrator.Update();
}
}
其他的
{
context.Database.Create();
种子(上下文);
SaveChanges();
}
}
受保护的虚拟空种子(TContext上下文)
{
}
}

内部密封类配置:dbmigtorinsconfiguration
{
公共配置()
{
AutomaticMiggerationsEnabled=真;
AutomaticMigrationDataLossAllowed=false;
SetSqlGenerator(“MySql.Data.MySqlClient”,新的MySql.Data.Entity.MySqlMigrationSqlGenerator());
}
受保护的覆盖无效种子(GumpDatabase上下文)
{
}
}

类GumpDatabaseInitializer:CreateOrMigrateDatabaseInitializer { 公共GumpDatabaseInitializer() { } 受保护的覆盖无效种子(GumpDatabase上下文) { context.Database.ExecuteSqlCommand(“在站点上创建唯一的索引名(名称)”); context.Database.ExecuteSqlCommand(“在序列上创建唯一的索引名(名称)”); context.Database.ExecuteSqlCommand(“在StationPartNumber(StationId,PartNumberId)上创建唯一索引StationPartNumber”); } } 最后

static void Main()
{
    Database.SetInitializer<GumpDatabase>(new GumpDatabaseInitializer());
static void Main()
{
SetInitializer(新的GumpDatabaseInitializer());

我想你差不多做到了-你可以查找
MigrateDatabaseToLatestVersion
的源代码(它是开源的)-它非常简单,就我所能看到的来说,它做的就是调用
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)
    {
    }
}
…并称之为

Database.SetInitializer(new GumpDatabaseInitializer());
编辑: 根据注释-DbMigrator不应运行两次。它总是检查(花费一点时间)并执行“空白”更新,然后继续运行。但是,如果您想删除该注释并在输入之前进行“检查”,则应该可以执行此操作(更改上面类似的部分)

(这是一个冗余/双重检查-其中一个if-s应该足够了。在那里放一个中断-看看到底发生了什么,它不应该进入-一旦数据库被迁移。正如我提到的,在测试它时工作正常

编辑:

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();
}
如果迁移是第一步,那么这就可以解决(中途)而不是播种问题。迁移必须是第一步,否则就会出现问题

您仍然需要正确地完成它-这是要点,如果不是您可能需要的全部-但是如果有任何问题,请使用MySQL等,这里可能还有一些后续工作

注意:如果您有一个db,仍然不会调用它,但它是空的。问题是两个不同的初始值设定项混合在一起。所以您必须解决这个问题-或者通过实现Create…在内部所做的事情(我们不能调用该调用)或者其他方法。

实际上应该是:

var migrator = new DbMigrator(_configuration);
if (!context.Database.CompatibleWithModel(false) || migrator.GetPendingMigrations().Any())
    migrator.Update();
因为如果我们有一个与我们的数据库模型无关的迁移,例如在我们的任何表中插入一行,迁移将不会执行。

要同时执行(种子和迁移)实际上,您只需将迁移与
MigrateDatabaseToLatestVersion
初始值设定项一起使用。当您为上下文启用迁移时,将创建一个从
DbMigrationsConfiguration
派生的
类,并且您可以重写该方法以种子y
class GumpDatabaseInitializer : CreateAndMigrateDatabaseInitializer<GumpDatabase, YourNamespace.Migrations.Configuration>
{
    protected override void Seed(GumpDatabase context)
    {
        context.Database.ExecuteSqlCommand("CREATE UNIQUE INDEX Name ON Stations (Name)");
    }
}
Database.SetInitializer(new GumpDatabaseInitializer());
var migrator = new DbMigrator(_configuration);
if (!context.Database.CompatibleWithModel(throwIfNoMetadata: false))
    if (migrator.GetPendingMigrations().Any())
        migrator.Update();
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();
}
var migrator = new DbMigrator(_configuration);
if (!context.Database.CompatibleWithModel(false) || migrator.GetPendingMigrations().Any())
    migrator.Update();
protected override void Seed(MyContext context) {
  // Add two entities with name "Foo" and "Bar".
  context.MyEntities.AddOrUpdate(
    e => e.Name,
    new MyEntity { Name = "Foo" },
    new MyEntity { Name = "Bar" }
  );
}
class MyContextInitializer
  : MigrateDatabaseToLatestVersion<MyContext, Migrations.Configuration> { }
public Configuration() {
  AutomaticMigrationsEnabled = true
}
public class CreateOrMigrateDatabaseInitializer<TContext, TConfiguration> : CreateDatabaseIfNotExists<TContext>, IDatabaseInitializer<TContext>
        where TContext : DbContext
        where TConfiguration : DbMigrationsConfiguration<TContext>, new()
    {

        void IDatabaseInitializer<TContext>.InitializeDatabase(TContext context)
        {
            if (context.Database.Exists())
            {
                if (!context.Database.CompatibleWithModel(throwIfNoMetadata: false))
                {
                    var migrationInitializer = new MigrateDatabaseToLatestVersion<TContext, TConfiguration>(true);
                    migrationInitializer.InitializeDatabase(context);
                }
            }

            base.InitializeDatabase(context);
        }
    }