資料植入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

注意

這項功能是在 EF Core 2.1 中新功能。This feature is new in EF Core 2.1.

不同於 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.

例如,這會設定種子資料,如BlogOnModelCreating:As 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.

這種類型的種子資料由管理移轉,需要產生而不需要連線到資料庫的指令碼,以更新資料庫中的資料。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.