網站首頁 編程語言 正文
一、什么是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方法。
四、總結
針對種子數據初始化,主要有上面的三種方式,比較推薦的是第一種和第三種,可以根據自己的使用情況來選擇適合自己的。
原文鏈接:https://www.cnblogs.com/dotnet261010/p/12359695.html
相關推薦
- 2022-05-27 Jmeter如何使用BeanShell取樣器調用Python腳本_python
- 2022-04-27 詳解linux里的backlog參數_Linux
- 2022-09-11 Shell之免交互的實現_linux shell
- 2022-09-24 關于R語言包的升級與降級問題_R語言
- 2024-03-04 JQ實現將div的滾動條滾動到指定子元素所在的位置
- 2022-07-14 超詳細講解C++的三種函數傳遞方式_C 語言
- 2022-01-21 如何保證Redis緩存與數據庫的一致性?
- 2022-09-21 Python實現斐波那契數列的多種寫法總結_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支