如何创建初始化程序来创建和迁移mysql数据库?
我一直在学习如何使用EF一个星期左右,并且我一直坚持创建/更新我的数据库的问题。 如果不存在,我可以创建一个初始化器来创建数据库:
static class Program { static void Main() { Database.SetInitializer(new GumpDatabaseInitializer()); .... class GumpDatabaseInitializer : CreateDatabaseIfNotExists { public GumpDatabaseInitializer() { } protected override void Seed(GumpDatabase context) { context.Database.ExecuteSqlCommand("CREATE UNIQUE INDEX Name ON Stations (Name)"); // Other stuff } }
或者我可以创建配置来迁移数据库
static class Program { static void Main() { Database.SetInitializer(new MigrateDatabaseToLatestVersion()); .... internal sealed class Configuration : DbMigrationsConfiguration { public Configuration() { AutomaticMigrationsEnabled = true; SetSqlGenerator("MySql.Data.MySqlClient", new MySql.Data.Entity.MySqlMigrationSqlGenerator()); } protected override void Seed(GumpDatabase context) { }
每个都正常工作,但我还没有想出办法做到这两点。 我可以通过更改SetInitializer调用在两个初始值设定项之间切换,但是如果我想创建数据库,如果它不存在,并且如果它是我该怎么做的话还要迁移它? 我需要创建自定义初始化程序吗?
谢谢
根据NSGaga答案编辑
class CreateOrMigrateDatabaseInitializer : CreateDatabaseIfNotExists, IDatabaseInitializer where TContext : DbContext where TConfiguration : DbMigrationsConfiguration, 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.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) { } }
和
internal sealed class Configuration : DbMigrationsConfiguration { public Configuration() { AutomaticMigrationsEnabled = true; AutomaticMigrationDataLossAllowed = false; SetSqlGenerator("MySql.Data.MySqlClient", new MySql.Data.Entity.MySqlMigrationSqlGenerator()); } protected override void Seed(GumpDatabase context) { } }
和
class GumpDatabaseInitializer : CreateOrMigrateDatabaseInitializer { 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)"); } }
最后
static void Main() { Database.SetInitializer(new GumpDatabaseInitializer());
我认为你几乎就在那里 – 你可以查找MigrateDatabaseToLatestVersion
的源代码(它的开源https://entityframework.codeplex.com/ ) – 它非常简单,它的function就是调用DbMigrator
– 就其而言我能看见。
所有你需要做的似乎是合并两个 – 使用一个或另一个作为基础,在那里添加其他function – 这应该工作正常我认为。
class CreateAndMigrateDatabaseInitializer : CreateDatabaseIfNotExists, IDatabaseInitializer where TContext : DbContext where TConfiguration : DbMigrationsConfiguration , 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 .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 CreateAndMigrateDatabaseInitializer());
…实际上,覆盖它(因为它是通用实现),就像你为CreateDatabaseIfNotExists
做的那样(你只需要配置额外的’param’) – 并且只提供’种子’。
class GumpDatabaseInitializer : CreateAndMigrateDatabaseInitializer { protected override void Seed(GumpDatabase context) { context.Database.ExecuteSqlCommand("CREATE UNIQUE INDEX Name ON Stations (Name)"); } }
……并称之为
Database.SetInitializer(new GumpDatabaseInitializer());
编辑:根据评论 – DbMigrator不应该运行两次。 它总是检查(花费一点时间)并进行“空白”更新并继续前进。 但是,如果您想要在进入之前删除它并“检查” – 这应该有效(更改上面的类似部分)……
var migrator = new DbMigrator(_configuration); if (!context.Database.CompatibleWithModel(throwIfNoMetadata: false)) if (migrator.GetPendingMigrations().Any()) migrator.Update();
(这是一个冗余/双重检查 – 其中一个if-s应该足够了。在那里rest一下 – 看看究竟发生了什么,它不应该进入 – 一旦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(); }
如果迁移首先进行,这可以解决(中途)非播种问题。 迁移必须是第一个,否则你就会遇到问题。
你仍然需要正确地做到这一点 – 如果不是你可能需要的话,这就是要点 – 但如果有任何问题与MySQL等,可能还有一些腿部工作。
注意:如果你有一个数据库,仍然没有调用播种,但它是空的。 问题是混合两种不同的初始化器。 所以你必须解决这个问题 – 通过实现内部的Create …(我们无法调用的那个)或其他东西。
实际上它应该是:
var migrator = new DbMigrator(_configuration); if (!context.Database.CompatibleWithModel(false) || migrator.GetPendingMigrations().Any()) migrator.Update();
因为如果我们有一个与我们的db模型无关的迁移,例如在我们的任何表中插入一行,就不会执行迁移。
要同时执行(种子和迁移),您实际上只需要使用MigrateDatabaseToLatestVersion
初始化程序进行迁移。 为上下文启用迁移时,将创建从DbMigrationsConfiguration
派生的Configuration
类,您可以覆盖Seed
方法DbMigrationsConfiguration
数据库设定种子。 请注意,此方法执行时数据库可能已包含种子数据,但AddOrUpdate
扩展方法可以方便地帮助您在数据库中进行“upserts”。
与一些其他数据库初始化器的Seed
方法相比,这是不同的,其中数据库仅在最初创建时播种。 但是,在使用迁移时,您可能希望在数据库更改时更改种子数据,并且使用MigrateDatabaseToLatestVersion
可以实现此目的。
要将种子组合与迁移相结合,您必须在新项目中执行以下步骤:
-
创建具有关联实体的代码优先
DbContext
-
在包管理器控制台中,执行命令
Enable-Migrations
-
在
Migrations
文件夹中,使用Seed
方法生成Configuration
类。 您可以修改此方法以为数据库设定种子: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" } ); }
-
您需要创建一个派生自
MigrateDatabaseToLatestVersion
的数据库初始化MigrateDatabaseToLatestVersion
:class MyContextInitializer : MigrateDatabaseToLatestVersion
{ } 您还必须通过在应用程序启动时调用
Database.SetInitializer(new MyContextInitializer())
或使用
元素在App.config
文件中配置初始化程序。 -
在生成的
Configuration
类的构造函数中,您可以启用自动迁移:public Configuration() { AutomaticMigrationsEnabled = true }
但是,在团队中,您可能不愿意这样做。 在这种情况下,您将必须创建初始迁移(除非它是在您执行
Enable-Migrations
时创建的)。 在包管理器中,执行命令Add-Migration InitialCreate
。 这将创建创建数据库所需的第一次迁移。
此时,您有一个带迁移的DbContext
和一个Seed
方法。
总结一下:启用迁移,使用MigrateDatabaseToLatestVersion
初始化程序,并在启用迁移时生成的Configuration
类中添加种子数据。
虽然MigrateDatabaseToLatestVersion实际上创建了数据库(如果它不存在),甚至允许您对其进行播种,但如果您已经有一个基于CreateDatabaseIfNotExists的工作解决方案和/或不想将其与测试存在种子数据进行复杂化,那么您可以只需使用下面的方法inheritance而不是CreateDatabaseIfNotExists :
public class CreateOrMigrateDatabaseInitializer : CreateDatabaseIfNotExists, IDatabaseInitializer where TContext : DbContext where TConfiguration : DbMigrationsConfiguration , new() { void IDatabaseInitializer .InitializeDatabase(TContext context) { if (context.Database.Exists()) { if (!context.Database.CompatibleWithModel(throwIfNoMetadata: false)) { var migrationInitializer = new MigrateDatabaseToLatestVersion(true); migrationInitializer.InitializeDatabase(context); } } base.InitializeDatabase(context); } }
这是基于之前的答案和OP自己的解决方案。 这也适用于其他提供商,但我只测试了SQL Server。
上述就是C#学习教程:如何创建初始化程序来创建和迁移mysql数据库?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1028351.html