如何创建初始创建和迁移mysql数据库? [英] How to create initializer to create and migrate mysql database?
问题描述
我一直在学习如何使用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屋!