資料植入Data Seeding

資料植入是以初始資料集填入資料庫的程式。Data seeding is the process of populating a database with an initial set of data.

有幾種方式可以在 EF Core 中完成:There are several ways this can be accomplished in EF Core:

  • 模型種子資料Model seed data
  • 手動遷移自訂Manual migration customization
  • 自訂初始化邏輯Custom initialization logic

模型種子資料Model seed data

不同于 EF6,在 EF Core 中,植入資料可以與實體類型相關聯,做為模型設定的一部分。Unlike in EF6, in EF Core, seeding data can be associated with an entity type as part of the model configuration. 然後 EF Core 的 遷移 可以自動計算將資料庫升級至新版本的模型時,必須套用的插入、更新或刪除作業。Then EF Core migrations can automatically compute what insert, update or delete operations need to be applied when upgrading the database to a new version of the model.

注意

當您決定應該執行哪一種作業來讓種子資料進入預期狀態時,遷移只會考慮模型變更。Migrations only considers model changes when determining what operation should be performed to get the seed data into the desired state. 因此,在遷移外部所執行之資料的任何變更都可能遺失或造成錯誤。Thus any changes to the data performed outside of migrations might be lost or cause an error.

例如,這會在中設定的種子資料 Blog OnModelCreatingAs an example, this will configure seed data for a Blog in OnModelCreating:

modelBuilder.Entity<Blog>().HasData(new Blog {BlogId = 1, Url = "http://sample.com"});

若要加入具有關聯性的實體,必須指定外鍵值:To add entities that have a relationship the foreign key values need to be specified:

modelBuilder.Entity<Post>().HasData(
    new Post() { BlogId = 1, PostId = 1, Title = "First post", Content = "Test 1" });

如果實體類型在陰影狀態中有任何屬性,則可以使用匿名類別來提供這些值:If the entity type has any properties in shadow state an anonymous class can be used to provide the values:

modelBuilder.Entity<Post>().HasData(
    new { BlogId = 1, PostId = 2, Title = "Second post", Content = "Test 2" });

擁有的實體類型可以用類似的方式植入:Owned entity types can be seeded in a similar fashion:

modelBuilder.Entity<Post>().OwnsOne(p => p.AuthorName).HasData(
    new { PostId = 1, First = "Andriy", Last = "Svyryd" },
    new { PostId = 2, First = "Diego", Last = "Vega" });

請參閱 完整的範例專案 ,以取得更多內容。See the full sample project for more context.

一旦將資料加入至模型之後,就應該使用 遷移 來套用變更。Once the data has been added to the model, migrations should be used to apply the changes.

提示

如果您需要將遷移套用為自動化部署的一部分,您可以建立可在執行前預覽的 SQL 腳本If you need to apply migrations as part of an automated deployment you can create a SQL script that can be previewed before execution.

或者,您可以使用 context.Database.EnsureCreated() 來建立包含種子資料的新資料庫,例如針對測試資料庫,或是在使用記憶體中提供者或任何非關聯資料庫時。Alternatively, you can use context.Database.EnsureCreated() to create a new database containing the seed data, for example for a test database or when using the in-memory provider or any non-relation database. 請注意,如果資料庫已經存在, EnsureCreated() 將不會在資料庫中更新架構或植入資料。Note that if the database already exists, EnsureCreated() will neither update the schema nor seed data in the database. 如果您打算使用遷移,則不應呼叫關係資料庫 EnsureCreated()For relational databases you shouldn't call EnsureCreated() if you plan to use Migrations.

模型種子資料的限制Limitations of model seed data

這種類型的種子資料是由遷移所管理,而且需要產生腳本來更新資料庫中已有的資料,而不需要連接到資料庫。This type of seed data is managed by migrations and the script to update the data that's already in the database needs to be generated without connecting to the database. 這會造成一些限制:This imposes some restrictions:

  • 您必須指定主鍵值(即使它通常是由資料庫所產生)。The primary key value needs to be specified even if it's usually generated by the database. 它將用來偵測遷移之間的資料變更。It will be used to detect data changes between migrations.
  • 如果主鍵以任何方式變更,則會移除先前植入的資料。Previously seeded data will be removed if the primary key is changed in any way.

因此,這項功能最適用于不需要在遷移之外變更的靜態資料,而且不會相依于資料庫中的任何其他資料,例如郵遞區號。Therefore this feature is most useful for static data that's not expected to change outside of migrations and does not depend on anything else in the database, for example ZIP codes.

如果您的案例包含下列任何一項,建議您使用上一節中所述的自訂初始化邏輯:If your scenario includes any of the following it is recommended to use custom initialization logic described in the last section:

  • 用於測試的暫存資料Temporary data for testing
  • 相依于資料庫狀態的資料Data that depends on database state
  • 需要資料庫產生的索引鍵值的資料,包括使用替代索引鍵做為身分識別的實體Data that needs key values to be generated by the database, including entities that use alternate keys as the identity
  • 需要自訂轉換 (的資料,不是由 值轉換) 處理,例如一些密碼雜湊Data that requires custom transformation (that is not handled by value conversions), such as some password hashing
  • 需要呼叫外部 API 的資料,例如 ASP.NET Core 身分識別角色和使用者建立Data that requires calls to external API, such as ASP.NET Core Identity roles and users creation

手動遷移自訂Manual migration customization

當您將所指定資料的變更轉換為、和的呼叫時,會將所指定之資料的變更 HasData 轉換成 InsertData() UpdateData() DeleteData()When a migration is added the changes to the data specified with HasData are transformed to calls to InsertData(), UpdateData(), and DeleteData(). 解決某些限制的其中一種方式 HasData ,是手動將這些呼叫或 自訂作業 加入至遷移作業。One way of working around some of the limitations of HasData is to manually add these calls or custom operations to the migration instead.

migrationBuilder.InsertData(
    table: "Blogs",
    columns: new[] { "Url" },
    values: new object[] { "http://generated.com" });

自訂初始化邏輯Custom initialization logic

執行資料植入的簡單、強大方式,是在 DbContext.SaveChanges() 主要應用程式邏輯開始執行之前使用。A straightforward and powerful way to perform data seeding is to use DbContext.SaveChanges() before the main application logic begins execution.

using (var context = new DataSeedingContext())
{
    context.Database.EnsureCreated();

    var testBlog = context.Blogs.FirstOrDefault(b => b.Url == "http://test.com");
    if (testBlog == null)
    {
        context.Blogs.Add(new Blog { Url = "http://test.com" });
    }
    context.SaveChanges();
}

警告

植入程式碼不應該是一般應用程式執行的一部分,因為這可能會在多個實例正在執行時造成並行處理問題,而且也會要求應用程式具有修改資料庫架構的許可權。The seeding code should not be part of the normal app execution as this can cause concurrency issues when multiple instances are running and would also require the app having permission to modify the database schema.

根據您的部署條件約束,可以用不同的方式執行初始化程式碼:Depending on the constraints of your deployment the initialization code can be executed in different ways:

  • 在本機執行初始化應用程式Running the initialization app locally
  • 使用主應用程式部署初始化應用程式、叫用初始化常式,以及停用或移除初始化應用程式。Deploying the initialization app with the main app, invoking the initialization routine and disabling or removing the initialization app.

這通常可以使用 發行設定檔進行自動化。This can usually be automated by using publish profiles.