如何创建初始创建和迁移mysql数据库? [英] How to create initializer to create and migrate mysql database?

查看:242
本文介绍了如何创建初始创建和迁移mysql数据库?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在学习如何使用EF一个星期左右,现在和我被困在创建/更新我的数据库的问题。我可以创造一个初始化创建数据库,如果它不存在:

 静态类节目
{
    静态无效的主要()
    {
        Database.SetInitializer&所述; GumpDatabase>(新GumpDatabaseInitializer());
....类GumpDatabaseInitializer:CreateDatabaseIfNotExists< GumpDatabase>
{
    公共GumpDatabaseInitializer()
    {
    }
    保护覆盖无效的种子(GumpDatabase上下文)
    {
        context.Database.ExecuteSqlCommand(创建唯一索引名称上的站(名称));
        // 其他的东西
    }
}

或者我可以创建一个配置迁移分贝

 静态类节目
{
    静态无效的主要()
    {
        Database.SetInitializer< GumpDatabase>(新MigrateDatabaseToLatestVersion< GumpDatabase,结构>());
....内部密封类配置:DbMigrationsConfiguration< GumpDatabase>
{
    公共配置()
    {
        AutomaticMigrationsEnabled = TRUE;
        SetSqlGenerator(MySql.Data.MySqlClient,新MySql.Data.Entity.MySqlMigrationSqlGenerator());
    }    保护覆盖无效的种子(GumpDatabase上下文)
    {    }

每个正常工作,但我还没有想出一个办法做到两者。我可以在两个初始化之间通过改变SetInitializer呼叫,但切换如果我想创建数据库,如果它不存在,也迁移它,如果它是我该怎么办?我需要创建一个自定义的初始化?

感谢

基于NSGaga回答修改

 类CreateOrMigrateDatabaseInitializer< TContext,TConfiguration> :CreateDatabaseIfNotExists< TContext>中IDatabaseInitializer< TContext>
    其中,TContext:的DbContext
    其中,TConfiguration:DbMigrationsConfiguration< TContext>中新()
{
    私人只读DbMigrationsConfiguration _configuration;
    公共CreateOrMigrateDatabaseInitializer()
    {
        _configuration =新TConfiguration();
    }
    公共CreateOrMigrateDatabaseInitializer(字符串连接)
    {
        Contract.Requires(string.IsNullOrEmpty(连接),连线!);        _configuration =新TConfiguration
        {
            TargetDatabase =新DbConnectionInfo(连接)
        };
    }
    无效IDatabaseInitializer< TContext> .InitializeDatabase(TContext上下文)
    {
        Contract.Requires(上下文= NULL,背景!);        如果(context.Database.Exists())
        {
            如果(context.Database.CompatibleWithModel(throwIfNoMetadata:FALSE))
            {
                VAR迁移=新DbMigrator(_configuration);
                migrator.Update();
            }
        }
        其他
        {
            context.Database.Create();
            种子(上下文);
            context.SaveChanges();
        }
    }
    受保护的虚拟无效种子(TContext上下文)
    {
    }
}

 内部密封类配置:DbMigrationsConfiguration< GumpDatabase>
{
    公共配置()
    {
        AutomaticMigrationsEnabled = TRUE;
        AutomaticMigrationDataLossAllowed = FALSE;
        SetSqlGenerator(MySql.Data.MySqlClient,新MySql.Data.Entity.MySqlMigrationSqlGenerator());
    }    保护覆盖无效的种子(GumpDatabase上下文)
    {
    }
}

 类GumpDatabaseInitializer:CreateOrMigrateDatabaseInitializer< GumpDatabase,Gump.Migrations.Configuration>
{
    公共GumpDatabaseInitializer()
    {
    }
    保护覆盖无效的种子(GumpDatabase上下文)
    {
        context.Database.ExecuteSqlCommand(创建唯一索引名称上的站(名称));
        context.Database.ExecuteSqlCommand(创建唯一索引名称ON序列(名称));
        context.Database.ExecuteSqlCommand(CREATE UNIQUE INDEX ON StationPartNumber StationPartNumbers(的stationID,PartNumberId));
    }
}

最后

 静态无效的主要()
{
    Database.SetInitializer&所述; GumpDatabase>(新GumpDatabaseInitializer());


解决方案

我觉得你是pretty得多 - 你可以查找源$ C ​​$ C为 MigrateDatabaseToLatestVersion (它是开源的 HTTP://entityframework.$c$cplex.com/ ) - 这是pretty简单,它做什么pretty多少是调用 DbMigrator - 据我可以看到。

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

 类CreateAndMigrateDatabaseInitializer< TContext,TConfiguration> :CreateDatabaseIfNotExists< TContext>中IDatabaseInitializer< TContext>
    其中,TContext:的DbContext
    其中,TConfiguration:DbMigrationsConfiguration< TContext>中新()
{
    私人只读DbMigrationsConfiguration _configuration;
    公共CreateAndMigrateDatabaseInitializer()
    {
        _configuration =新TConfiguration();
    }
    公共CreateAndMigrateDatabaseInitializer(字符串连接)
    {
        Contract.Requires(string.IsNullOrEmpty(连接),连线!);        _configuration =新TConfiguration
        {
            TargetDatabase =新DbConnectionInfo(连接)
        };
    }
    无效IDatabaseInitializer< TContext> .InitializeDatabase(TContext上下文)
    {
        Contract.Requires(上下文= NULL,背景!);        VAR迁移=新DbMigrator(_configuration);
        migrator.Update();        //使用'CreateDatabaseIfNotExists前进的'种子'
        base.InitializeDatabase(上下文);
    }
    保护覆盖无效的种子(TContext上下文)
    {
    }
}

这样称呼它......

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

...实际上,覆盖它(因为它是通用实现)就像你在做的 CreateDatabaseIfNotExists (你只需要额外的'参数'的配置) - 和公正的供应种子'。

 类GumpDatabaseInitializer:CreateAndMigrateDatabaseInitializer< GumpDatabase,YourNamespace.Migrations.Configuration>
{
    保护覆盖无效的种子(GumpDatabase上下文)
    {
        context.Database.ExecuteSqlCommand(创建唯一索引名称上的站(名称));
    }
}

...并调用它像

  Database.SetInitializer(新GumpDatabaseInitializer());

编辑:
根据意见 - DbMigrator不应该运行两次。它总是检查(花一点时间),并做了空白和更新上移动。但是以防万一,如果你想删除,并在进入之前检查 - 这应该工作(改变以上类似的一块)...

  VAR迁移=新DbMigrator(_configuration);
如果(context.Database.CompatibleWithModel(throwIfNoMetadata:FALSE))
    如果(migrator.GetPendingMigrations()。任何())
        migrator.Update();

(这是一个冗余/仔细检查 - 在若-S之一应该是足够把休息那里 - 看看到底发生了什么,它不应该进去 - 一旦DB是迁移正如我所说,作品很好,当我进行测试。

编辑:

与...更换 InitializeDatabase 内部

  VAR doseed = context.Database.Exists();
//&功放;&安培;新DatabaseTableChecker()AnyModelTableExists(上下文)。
//检查是否种子 - 我们缺乏'的'AnyModelTableExists' - 如果需要,可以复制/完成,否则...VAR迁移=新DbMigrator(_configuration);
//如果(!doseed || context.Database.CompatibleWithModel(throwIfNoMetadata:FALSE))
    如果(migrator.GetPendingMigrations()。任何())
        migrator.Update();//使用'CreateDatabaseIfNotExists前进的'种子'
base.InitializeDatabase(上下文);
如果(doseed)
{
    种子(上下文);
    context.SaveChanges();
}

这能解决(中途)未播种 - 如果移民先行。和迁移必须是第一,否则,你的问题。

您还需要正确地做到这一点 - 这是如果不是所有你可能需要的要点 - 但如果任何问题瓦特/ MySQL的等等,可能是一些更多的腿部在这里工作。

注意:不过播种,如果你有一个数据库不叫,但它是空的。问题是混合两种不同的初始化的。所以,你必须要继续说出来 - 无论是通过实现什么创造... ...没有内部(即调用我们不能调用)或别的东西。

I have been learning how to use EF for a week or so now and am stuck on the issue of creating/updating my database. I am able to create an initializer to create the database if it is not there:

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
    }
}

Or I can create a Configuration to migrate the db

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

    }

Each works correctly but I haven't figured out a way to do both. I can switch between the two initializers by changing the SetInitializer call but if I want to create the database if it is not there and also migrate it if it is what do I do? Do I need to create a custom initializer?

Thanks

Edit based on NSGaga answer

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

and

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

and

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)");
    }
}

and finally

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

解决方案

I think you're pretty much there - you can lookup the source code for MigrateDatabaseToLatestVersion (it's open source http://entityframework.codeplex.com/) - it's pretty simplistic, what it does pretty much is call the DbMigrator - as far as I could see.

All you have to do seems is to merge the two - use one or the other as a basis, add other functionality in there - that should work fine I think.

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

call it like this...

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

...actually, override it (since it's generic implementation) like you were doing for CreateDatabaseIfNotExists (you just have extra 'param' for Configuration) - and just supply the 'Seed'.

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

...and call it something like

Database.SetInitializer(new GumpDatabaseInitializer());

EDIT: Based on the comments - DbMigrator should not run twice. It always checks (spends a bit of time) and does a 'blank' update and moves on. However just in case if you'd like to remove that and 'check' before entering - this should work (change the similar piece above)...

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

(this is a redundant / double-check - one of the if-s should be enough. Put a break there - and see exactly what's happening, it should not get in - once Db is migrated. As I mentioned, works fine when I test it.

EDIT:

Replace the inside of InitializeDatabase with...

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();
}

This works around (half-way) not-seeding - if migration goes first. And migrations have to be first, otherwise you have issues.

You still need to do it properly - this is the gist if not all you might need - but if any issues w/ MySQL etc., probably some more leg work here.

Note: Still seeding doesn't call if you have a db, but it's empty. Problem is mixing of the two different initializers. So you'll have to work that out - either by implementing what Create... does inside (that call we can't call) or something else.

这篇关于如何创建初始创建和迁移mysql数据库?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆