在Entity Framework 4.3中逐步种子数据的最佳方法

Jim*_*ell 41 entity-framework ef-migrations entity-framework-4.3

我一直在现有数据库上使用Entity Framework 4.3,我有几个我想要满足的场景.

首先,如果我删除我的数据库,我希望EF从头开始重新创建 - 我已成功使用CreateDatabaseIfNotExists数据库初始化程序.

其次,如果我更新我的模型并且数据库已经存在,我希望数据库自动更新 - 我已成功使用Entity Framework 4.3 Migrations.

所以这是我的问题.假设我在模型中添加了一个新表,这需要一些参考数据,这是确保在数据库intialiser运行时以及迁移运行时创建此数据的最佳方法.我的愿望是,当我从头开始创建数据库时,以及当数据库因迁移运行而更新时,会创建数据.

在一些EF迁移示例中,我看到人们在迁移的UP方法中使用SQL()函数来创建种子数据,但如果可能,我宁愿使用上下文来创建种子数据(正如您在大多数数据库初始化示例中看到的那样)因为我觉得很奇怪,当EF的整个想法抽象出来时,你会使用纯粹的SQL.我曾尝试在UP方法中使用上下文,但出于某种原因,当我尝试在创建表的调用下直接添加种子数据时,它并不认为迁移中创建的表存在.

任何智慧都非常感激.

Lad*_*nka 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" }
        //    );
        //
    }
}
Run Code Online (Sandbox Code Playgroud)

迁移种子数据的方式效率不高,因为它应该用于一些非常基本的种子.每个新版本的更新都将通过整个集合并尝试更新现有数据或插入新数据.如果不使用AddOrUpdate扩展方法,则必须手动确保仅在数据尚未存在时才将数据播种到数据库.

如果你想要有效的播种方式,因为你必须播种大量数据,你会得到更好的结果:

public partial class SomeMigration : DbMigration
{
    public override void Up()
    {
        ...
        Sql("UPDATE ...");
        Sql("INSERT ...");
    }

    public override void Down()
    {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 实际上,您可以在Up方法中创建上下文,并使用AddOrUpdate插入行.但是,这不会包含在迁移事务中,因此可能会导致问题.此外,当模型更改时,无法保证将来编译. (8认同)
  • @Ladislav你对EF的深度知识继续令我惊讶,你有没有考虑过写一本关于这个主题的书,也许还能解决你在这里遇到的常见误解? (8认同)

Rog*_*ger 32

我不建议Sql()在你的Up()方法中使用调用,因为(IMO)这实际上是针对没有内置函数的实际迁移代码,而不是种子代码.

我喜欢将种子数据视为未来可能发生变化的事情(即使我的模式没有),所以我只是在种子函数中对所有插入进行"防御性"检查,以确保操作不会触发先前.

考虑一种情况,其中您有一个"类型"表,该表以3个条目开头,但之后您添加第4个.您不应该需要"迁移"来解决这个问题.

使用Seed()也为您提供了完整的上下文,这比使用Sql()Ladislav演示的方法中的普通sql字符串要好得多.

另外,请记住,对迁移代码和种子代码使用内置EF方法的好处是您的数据库操作保持平台无关.这意味着您的架构更改和查询能够在Oracle,Postgre等上运行.如果您编写实际的原始SQL,那么您可能会不必要地锁定自己.

您可能不太关心这一点,因为90%的使用EF的人只会访问SQL Server,但我只是把它扔到那里给你一个不同的解决方案.

  • 我认为"Up"方法是做"参考"数据的好地方 - 参考数据通常意味着应用程序需要数据用于某种逻辑. (8认同)