在 Entity Framework 4.3 中增量播种数据的最佳方法

Posted

技术标签:

【中文标题】在 Entity Framework 4.3 中增量播种数据的最佳方法【英文标题】:Best way to incrementally seed data in Entity Framework 4.3 【发布时间】:2012-03-09 16:35:49 【问题描述】:

我一直在现有数据库上使用 Entity Framework 4.3,并且我正在尝试满足几个场景。

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

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

所以这是我的问题。假设我向我的模型添加了一个新表,它需要一些参考数据,这是确保在数据库初始化程序运行和迁移运行时创建这些数据的最佳方法。我的愿望是,当我从头开始创建数据库以及由于迁移运行而更新数据库时,数据就会被创建。

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

非常感谢任何智慧。

【问题讨论】:

【参考方案1】:

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

我喜欢将种子数据视为未来可能会改变的东西(即使我的架构没有改变),所以我只是简单地围绕我在种子函数中的所有插入编写“防御性”检查,以确保操作之前没有开火。

假设您有一个“类型”表,该表以 3 个条目开始,但随后又添加了第 4 个条目。您不需要“迁移”来解决这个问题。

使用 Seed() 还可以为您提供完整的上下文,这比在 Ladislav 演示的 Sql() 方法中使用纯 sql 字符串要好得多。

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

您可能不太担心这一点,因为 90% 的使用 EF 的人只会使用 SQL Server,但我只是把它扔在那里,让您对解决方案有不同的看法。

【讨论】:

我认为“Up”方法是做“参考”数据的好地方 - 参考数据通常意味着应用程序需要该数据用于某种逻辑。【参考方案2】:

如果您想使用实体来播种数据,您应该在迁移配置中使用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()
    
        ...
    

【讨论】:

您实际上可以在 Up 方法中创建上下文并使用 AddOrUpdate 插入行。但是,这不会包含在迁移事务中,因此可能会导致问题。此外,不保证将来模型更改时可以编译。 我尝试在 Up 方法中创建一个上下文,但它抛出了一个错误,说该表不存在。我将在“Up”方法中尝试 SQL。 @Ladislav 你对 EF 的深入了解让我感到惊讶,你有没有考虑写一本关于这个主题的书,也许可以解决你在这里遇到的常见误解? 在使用这种方法时必须小心设置 AutomaticMigrationDataLossAllowed = false。如果您不这样做,您可能会丢失数据库中的数据。使用自动迁移时发生在我身上。最好使用种子方法 IMO。 有没有办法从生产环境调用该代码?我不确定如何在目标服务器上进行最初的数据库播种。我需要创建一个角色(“管理员”)并确保其中有几个用户。

以上是关于在 Entity Framework 4.3 中增量播种数据的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

Entity Framework 4.3 多应用数据库迁移策略

csharp 如何首先使用迁移向Entity Framework 4.3代码中的列添加描述?

将 SQL Server Compact 4.0.0.1 与 Entity Framework 4.3 一起使用

使用 Entity Framework Migrations 4.3 时如何显式命名数据库

Entity Framework Core 性能优化

Entity Framework Core 性能优化