对EF自动迁移和种子播种的困惑 – 每个节目开始播种
我最近更改了一个应用程序使用以下的开发:
DropCreateDatabaseIfModelChanges<Context>
使用:
public class MyDbMigrationsConfiguration: DbMigrationsConfiguration<GrsEntities> { public MyDbMigrationsConfiguration() { AutomaticMigrationsEnabled = true; AutomaticMigrationDataLossAllowed = true; } }
在我的数据库环境中,我有:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { // Tell Code First to ignore PluralizingTableName convention // If you keep this convention then the generated tables will have pluralized names. modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); //set the initializer to migration Database.SetInitializer(new MigrateDatabaseToLatestVersion<GrsEntities, MigrationConfig>()); }
我已经覆盖DbMigrationsConfiguration中的种子(上下文)使用AddOrUpdate扩展,其中我刚刚使用添加之前种子放置数据库(DropCreateDatabaseIfModelChanges)。
我的困惑是,无论DbContext有什么变化,Migration都会在应用程序的每一次启动时运行。 每次启动应用程序(库运行一个服务)时,初始化程序都像Seed一样运行。 我预期的行为是检查是否需要迁移(幕后检查模型是否匹配物理数据库),然后更新任何新的/删除的表/列,只有在发生了变化时才运行种子。
在我的testing中,种子每次都运行,这是可行的,但看起来效率低下,并不是我所期望的。 不幸的是,MSDN文档是相当有限的。
我完全滥用MigrateDatabaseToLatestVersion吗? 有没有什么办法来获得我期望的行为(即只有在有模型更改的情况下才会种子)还是应该更改我的种子方法以期在每次启动应用程序时运行?
Seed方法仅在数据库更改时才运行,这一点对EF 4.1中的数据库初始化程序非常有限。 这是有限制的,因为有时你需要更新种子数据而不更改数据库,但是为了实现这一点,必须人为地使数据库看起来像已经改变了。
随着迁移使用种子变得有点不同,因为它不能再假定数据库是开始空的 – 这毕竟是迁移点。 因此,Migrations中的Seed方法必须假定数据库存在并且可能已经有数据,但可能需要更新数据以考虑迁移对数据库所做的更改。 因此使用AddOrUpdate。
所以现在我们有一个情况,必须写入Seed来考虑现有的数据,这意味着确实没有必要延续EF 4.1 Seed方法的限制,这样就不得不使数据库看起来像已经改变只是为了让种子运行。 因此,Seed现在每次在应用程序域中首次使用上下文时都会运行。 这不应该改变Seed实施的方式,因为它需要处理数据已经存在的情况。
如果由于有很多种子数据而导致性能问题,那么通常很容易将检查添加到查询数据库的Seed方法中,以确定在执行之前需要完成多less工作。
我有点赞同Arthur Vickers的回应,但是IMO种子是用于DbMigrations的,我不希望Seed方法每次检查一切,例如,如果我有4个迁移,那么我将需要testing哪些数据必须播种,将至less有4个数据库点击。 如果你仍然希望只有在应用迁移时运行Seed方法,像我一样,我自己实现了IDatabaseInitializer
策略
public class CheckAndMigrateDatabaseToLatestVersion<TContext, TMigrationsConfiguration> : IDatabaseInitializer<TContext> where TContext : DbContext where TMigrationsConfiguration : DbMigrationsConfiguration<TContext>, new() { public virtual void InitializeDatabase(TContext context) { var migratorBase = ((MigratorBase)new DbMigrator(Activator.CreateInstance<TMigrationsConfiguration>())); if (migratorBase.GetPendingMigrations().Any()) migratorBase.Update(); } }
另一种select是在种子方法的运行时加载一个自定义数据库初始化类。 生产应用程序然后可以加载一个虚拟初始化器,而开发应用程序可以加载真正的初始化器。 你可以使用Unity / MEF
// Unity Dependency Injection Prop [Dependency] property IMyInitializer initializer; protected override Seed(YourContextClass context) { initializer.Seed(context); }
就是这样 一旦将生产数据库中的数据库设置为虚拟数据库,您就可以切换初始化程序,这样做什么也不做。