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 ...(我们无法调用的调用)或其他内容来解决这个问题.