我一直在现有数据库上使用Entity Framework 4.3,并且我有几个我想要满足的场景。
首先,如果我删除了我的数据库,我希望EF从头开始重新创建 - 我已成功使用了CreateDatabaseIfNotExists数据库初始化程序。
其次,如果我更新我的模型并且数据库已经存在,我希望数据库能够自动更新 - 我已成功使用Entity Framework 4.3迁移。
所以这是我的问题。假设我在模型中添加了一个新表,需要一些参考数据,这是确保在数据库intialiser运行时以及迁移运行时创建此数据的最佳方法。我的愿望是,当我从头开始创建数据库时,以及当数据库因迁移运行而更新时,数据会被创建。
在一些EF迁移示例中,我看到人们在迁移的UP方法中使用SQL()函数来创建种子数据,但如果可能,我宁愿使用上下文来创建种子数据(如您在大多数数据库中看到的那样)初始化示例)因为我觉得很奇怪,当EF的整个想法抽象出来时,你会使用纯粹的SQL。我曾尝试在UP方法中使用上下文,但出于某种原因,当我尝试在调用下直接添加种子数据以创建表时,它并不认为迁移中创建的表存在。
任何智慧都非常感激。
答案 0 :(得分:55)
如果要使用实体来播种数据,则应在迁移配置中使用Seed
方法。如果您生成新项目Enable-Migrations
,您将获得此配置类:
internal sealed class Configuration : DbMigrationsConfiguration<YourContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(CFMigrationsWithNoMagic.BlogContext context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data. E.g.
//
// context.People.AddOrUpdate(
// p => p.FullName,
// new Person { FullName = "Andrew Peters" },
// new Person { FullName = "Brice Lambson" },
// new Person { FullName = "Rowan Miller" }
// );
//
}
}
迁移种子数据的方式效率不高,因为它应该用于一些非常基本的种子。每个新版本的更新都将通过整个集合并尝试更新现有数据或插入新数据。如果您不使用AddOrUpdate
扩展方法,则必须手动确保数据仅在数据尚未出现时才被播种到数据库。
如果你想要有效的播种方式,因为你必须播种大量的数据,你会得到更好的结果:
public partial class SomeMigration : DbMigration
{
public override void Up()
{
...
Sql("UPDATE ...");
Sql("INSERT ...");
}
public override void Down()
{
...
}
}
答案 1 :(得分:32)
我不建议在Sql()
方法中使用Up()
调用,因为(IMO)这实际上是针对没有内置函数的实际迁移代码,而不是种子代码。
我喜欢将种子数据视为未来可能发生变化的事情(即使我的模式没有),所以我只是在种子函数中的所有插入内部编写“防御性”检查以确保操作之前没有开火。
考虑一个场景,其中有一个“类型”表,该表以3个条目开头,但之后您又添加了第4个。您不应该需要“迁移”来解决这个问题。
使用Seed()
还可以为您提供完整的上下文,这比使用Ladislav演示的Sql()
方法中的普通sql字符串要好得多。
另外,请记住,对迁移代码和种子代码使用内置EF方法的好处是您的数据库操作保持平台无关。这意味着您的架构更改和查询能够在Oracle,Postgre等上运行。如果您编写实际的原始SQL,那么您可能会不必要地锁定自己。
您可能不太关心这一点,因为90%的使用EF的人只能访问SQL Server,但我只是把它扔到那里给你一个不同的解决方案。