首頁 > 軟體

Entity Framework Core種子資料Data-Seeding

2022-03-25 13:00:49

一、什麼是Data-Seeding

Data-Seeding是EntityFrameworkCore 2.1以上版本新增加的特性。在專案剛開始的時候,我們往往是需要初始化一些基礎資料到資料庫中,通過Data-Seeding特性就可以實現這一功能。本篇文章我們將講解如何進行資料初始化。

二、初始化方法

具體的資料初始化方法分為如下三種:

  • 模型中設定。這種是通過呼叫HasData()方法。
  • 手動遷移時新增。
  • 自定義初始化邏輯。

下面我們分別來講解如何使用這三種方式進行資料遷移。

1、模型中設定

這種方式是通過呼叫HasData()方法實現的。這種也是我在專案開發過程中,經常使用的。這種方式是在資料上下文類中重寫OnModelCreating()方法,我們先看HasData()方法的定義:

可以看到,方法的引數可以是Blog型別的陣列,具體程式碼如下:

using EFCore.Model;
using Microsoft.EntityFrameworkCore;

namespace EFCore.Data
{
    /// <summary>
    /// 資料上下文
    /// </summary>
    public class EFDbContext:DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("Data Source=.;Initial Catalog=EFTest;User ID=sa;Password=123456;");
        }

        public DbSet<Blog> Blogs { get; set; }


        /// <summary>
        /// 重寫OnModelCreating方法
        /// </summary>
        /// <param name="modelBuilder"></param>
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // 針對Blog實體新增種子資料
            modelBuilder.Entity<Blog>().HasData(
                new Blog()
                {
                    // Id欄位要賦值,否則會報錯
                    Id=1,
                    Name="ef core"
                },
                new Blog()
                {
                    Id=2,
                    Name="ASP.NET Core"
                },
                new Blog()
                {
                    Id=3,
                    Name="圖解資料結構"
                }
                );
            base.OnModelCreating(modelBuilder);
        }
    }
}

我們注意到:預設情況下會自動設定Id列為主鍵,並且是自動增長的。但是這裡要設定Id的值,即使Id是自動生成的主鍵,否則會報下圖所示的錯誤:

新增完種子資料以後,我們執行程式,檢視輸出結果:

檢視資料庫:

這樣就生成了資料庫和表,而且表裡面也有了初始化資料。

假如這時候我們想增加一條資料,程式碼如下:

using EFCore.Model;
using Microsoft.EntityFrameworkCore;

namespace EFCore.Data
{
    /// <summary>
    /// 資料上下文
    /// </summary>
    public class EFDbContext:DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("Data Source=.;Initial Catalog=EFTest;User ID=sa;Password=123456;");
        }

        public DbSet<Blog> Blogs { get; set; }


        /// <summary>
        /// 重寫OnModelCreating方法
        /// </summary>
        /// <param name="modelBuilder"></param>
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // 針對Blog實體新增種子資料
            modelBuilder.Entity<Blog>().HasData(
                new Blog()
                {
                    // Id欄位要賦值,否則會報錯
                    Id=1,
                    Name="ef core"
                },
                new Blog()
                {
                    Id=2,
                    Name="ASP.NET Core"
                },
                new Blog()
                {
                    Id=3,
                    Name="圖解資料結構"
                },
                // 新增加一條資料
                new Blog()
                {
                    Id=4,
                    Name="C#高階程式設計"
                }
                
                );
            base.OnModelCreating(modelBuilder);
        }
    }
}

這時候還能不能用剛才的方法呢?我們這時在執行程式,檢視結果:

這時候程式執行失敗了,而且表裡面的資料也沒有增加。這說明context.Database.EnsureCreated()方法只有在第一次執行的時候才會有效,以後資料進行更改後就無效了。那麼有什麼方式可以實現呢?這時只有通過命令列進行遷移或者通過context.Database.Migrate方法呼叫生成的遷移類才能對資料的更改有效。

我們把剛才生成的資料庫刪掉,新增加的那條資料註釋掉,然後使用命令列遷移的方式生成資料庫表,首先新增遷移:

然後更新資料庫:

更新完資料庫以後,我們在HasData()方法裡面新增一條資料,然後再次執行上面的新增遷移和更新資料庫的命令,發現這時候資料庫裡面會新增新增加的資料。

在執行完第二次新增遷移命令後,如果不使用更新資料庫命令,也可以通過程式碼的方式進行遷移,這就是呼叫context.Database.Migrate命令,程式碼如下:

using EFCore.Data;
using Microsoft.EntityFrameworkCore;
using System;

namespace EFCore.Con
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            EFDbContext dbContext = new EFDbContext();
            // 遷移
            dbContext.Database.Migrate();
            //bool tfTrue = dbContext.Database.EnsureCreated();
            //if(tfTrue)
            //{
            //    Console.WriteLine("資料庫建立成功!");
            //}
            //else
            //{
            //    Console.WriteLine("資料庫建立失敗!");
            //}

            Console.ReadKey();
        }
    }
}

這時會自動呼叫最新的遷移檔案去更新資料庫。

注意:呼叫該方法對資料的更改只有在遷移時才能生效,也就是說只有通過命令進行遷移或者通過context.Database.Migrate方法呼叫生成的遷移類才能對資料更改有效。而呼叫context.Database.EnsureCreated()方法只有在第一次執行的時候才有效,但資料進行更改後將無效。

這種方式有兩種限制:

  • 必須指定主鍵的值(即使主鍵由資料庫自動生成也要指定值)。
  • 新增的必須是靜態資料,沒有任何的依賴。比如新增的Id主鍵的值在其它表裡面有參照就不可以。

2、手動遷移時新增

這種方式在這裡不進行講解,有興趣的可以參考微軟的官方檔案。

3、自定義初始化邏輯

執行資料種子設定的一種簡單而有效的方法是在主應用程式邏輯開始執行之前使用使用DbContext.SaveChanges()。程式碼如下:

using EFCore.Data;
using EFCore.Model;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;

namespace EFCore.Con
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            //EFDbContext dbContext = new EFDbContext();
            //// 遷移
            //dbContext.Database.Migrate();
            ////bool tfTrue = dbContext.Database.EnsureCreated();
            ////if(tfTrue)
            ////{
            ////    Console.WriteLine("資料庫建立成功!");
            ////}
            ////else
            ////{
            ////    Console.WriteLine("資料庫建立失敗!");
            ////}

            #region 使用自定義初始化邏輯
            using(EFDbContext context=new EFDbContext())
            {
                context.Database.EnsureCreated();

                var testBlog = context.Blogs.FirstOrDefault(p => p.Name == "C#");
                if(testBlog == null)
                {
                    // 新增資料
                    context.Blogs.Add(new Blog()
                    {
                        Name = "C#"
                    });
                }

                // 儲存資料
                context.SaveChanges();
            }
            #endregion
            Console.ReadKey();
        }
    }
}

通過這種自定義邏輯的方式也可以新增種子資料。如果HasData()方法裡面新增了種子資料,那麼會先把HasData()方法裡面的種子資料新增到資料庫中。如果沒有名稱為C#的資料,則還會在新增一條資料。

如果有了該資料,就不會再新增了。

注意:這種方式新增資料的時候就不能再給主鍵Id賦值了,因為是先生成資料庫,自動設定Id為主鍵,在新增資料的時候會自動賦值。

三、Data-Seeding本質

  • 當呼叫HasData()方法首次遷移時,實質上是呼叫MigrationBuilder類中InsertData方法進行插入。
  • 當呼叫HasData()方法更改資料(未更改主鍵)時,實質上是呼叫MigrationBuilder類中UpdateData方法進行更新操作。
  • 當呼叫HasData()方法移除資料或更改主鍵時,實質上是呼叫MigrationBuilder類中DeleteData方法進行刪除操作或者刪除和更新操作。

1、首次遷移

我們在第一次執行完新增遷移命令以後,會生成一個遷移檔案,如下圖所示:

可以看到這時就是呼叫的InsertData方法來新增資料。

2、修改不是主鍵的資料

我們修改資料,將ef core修改為ef core 3.1.1,如下圖所示:

修改完以後我們在執行遷移命令,如圖所示:

這時在去看生成的遷移檔案:

這時執行的就是UpdateData方法。

3、刪除資料

接著我們把Id為1的資料在程式碼裡面註釋掉模擬刪除操作,在執行遷移命令:

在看生成的遷移檔案:

可以看到這次就是執行的DeleteData方法。

4、修改主鍵資料

我們在把Id為2的資料修改為6:

在執行遷移:

檢視生成的遷移檔案:

這次就是先執行DeleteData方法,然後在執行InsertData方法。

四、總結

針對種子資料初始化,主要有上面的三種方式,比較推薦的是第一種和第三種,可以根據自己的使用情況來選擇適合自己的。

到此這篇關於Entity Framework Core種子資料Data-Seeding的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com