網站首頁 編程語言 正文
一、合并和遷移
1、合并
合并是指“新的實體模型映射到數據庫中,更新其結構”,例如:
新增了實體類,表現在數據庫中就是新增加實體類對應的數據表。
刪除了實體類,表現在數據庫中就是刪除了實體類對應的數據表。
在一個已經存在的實體類中增加屬性,表現在數據庫中就是在實體類對應的數據表中新增加字段。
在一個已經存在的實體類中刪除屬性,表現在數據庫中就是在實體類對應的數據表中刪除字段。
修改一個已經存在的實體類中屬性的名稱或類型,表現在數據庫中就是修改實體類對應的數據表中字段的名稱或類型。
2、遷移
遷移是指“在更新數據庫結構時,把老結構中的數據遷移到新結構中”。
二、遷移前的準備工作
搭建項目結構,整體的項目結構包括一個控制臺應用程序和兩個類庫,項目結構如下:
其中EF.Application是控制臺程序,EF.FluentAPI和EF.Model是類型,EF.Model里面存的是實體類,EF.FluentAPI是實體類的Map類,用來設置FluentAPI。
Student類結構如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EF.Model { public class Student { public int StudentID { get; set; } public string StudentName { get; set; } public int Age { get; set; } public string Sex { get; set; } } }
StudentMap類結構如下:
using EF.Model; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Data.Entity.ModelConfiguration; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EF.FluentAPI { ////// 使用FluentAPI配置 /// public class StudentMap :EntityTypeConfiguration{ public StudentMap() { // 配置數據庫中生成的表的名稱 this.ToTable("Students"); // 設置StudentID列自動增長 this.Property(p => p.StudentID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); // 設置StudentID列作為主鍵 this.HasKey(p => p.StudentID); // 設置StudentName列的類型是nvarchar,最大長度是50,必須的 this.Property(p => p.StudentName).HasColumnType("nvarchar").HasMaxLength(50).IsRequired(); // 設置Age列是必須的 this.Property(p => p.Age).IsRequired(); // 設置Sex的類型是nvarchar this.Property(p => p.Sex).HasColumnType("nvarchar").IsRequired(); } } }
EF上下文類結構:
using System; using System.Collections.Generic; using System.Data.Entity; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EF.FluentAPI { public class EFDbContext:DbContext { public EFDbContext() : base("name=CodeFirstApplication") { } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add(new StudentMap()); } } }
數據庫連接字符串:【注意:在EF.Application和EF.FluentAPI的App.config里面都要添加上該連接字符串】
控制臺程序:
using EF.FluentAPI; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using EF.Model; namespace EF.Application { class Program { static void Main(string[] args) { Console.WriteLine("請輸入學生姓名:"); string studentName = Console.ReadLine().Trim(); Console.WriteLine("請輸入學生年齡:"); int age = 0; if (!int.TryParse(Console.ReadLine().Trim(), out age)) { Console.WriteLine("年齡只能輸入正整數,請重新輸入:"); return; } Console.WriteLine("請輸入學生性別(男/女):"); string sex = Console.ReadLine().Trim(); using (var context = new EFDbContext()) { Student student = new Student() { StudentName=studentName, Age=age, Sex=sex }; context.Entry(student).State = System.Data.Entity.EntityState.Added; // 保存 context.SaveChanges(); } Console.Write("添加成功"); Console.ReadKey(); } } }
運行程序:
查看數據庫:
其中生成的表__MigrationHistory用來記錄每次的遷移。
三、遷移
現在我們在Student實體類中增加Grade字段,整體項目做如下的改動:
Student類:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EF.Model { public class Student { public int StudentID { get; set; } public string StudentName { get; set; } public int Age { get; set; } public string Sex { get; set; } // 新增加Grade字段,用來實現數據遷移 public string Grade { get; set; } } }
StudentMap類:
using EF.Model; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Data.Entity.ModelConfiguration; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EF.FluentAPI { ////// 使用FluentAPI配置 /// public class StudentMap :EntityTypeConfiguration{ public StudentMap() { // 配置數據庫中生成的表的名稱 this.ToTable("Students"); // 設置StudentID列自動增長 this.Property(p => p.StudentID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); // 設置StudentID列作為主鍵 this.HasKey(p => p.StudentID); // 設置StudentName列的類型是nvarchar,最大長度是50,必須的 this.Property(p => p.StudentName).HasColumnType("nvarchar").HasMaxLength(50).IsRequired(); // 設置Age列是必須的 this.Property(p => p.Age).IsRequired(); // 設置Sex的類型是nvarchar this.Property(p => p.Sex).HasColumnType("nvarchar").IsRequired(); // 設置Grade字段是必須的 this.Property(p => p.Grade).HasColumnType("varchar").HasMaxLength(16).IsRequired(); } } }
控制臺:
using EF.FluentAPI; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using EF.Model; namespace EF.Application { class Program { static void Main(string[] args) { Console.WriteLine("請輸入學生姓名:"); string studentName = Console.ReadLine().Trim(); Console.WriteLine("請輸入學生年齡:"); int age = 0; if (!int.TryParse(Console.ReadLine().Trim(), out age)) { Console.WriteLine("年齡只能輸入正整數,請重新輸入:"); return; } Console.WriteLine("請輸入學生性別(男/女):"); string sex = Console.ReadLine().Trim(); Console.WriteLine("請輸入年級:"); string grade = Console.ReadLine().Trim(); using (var context = new EFDbContext()) { Student student = new Student() { StudentName=studentName, Age=age, Sex=sex, Grade=grade }; context.Entry(student).State = System.Data.Entity.EntityState.Added; // 保存 context.SaveChanges(); } Console.Write("添加成功"); Console.ReadKey(); } } }
啟用數據遷移:
1、打開遷移
在程序包管理器控制臺中輸入:Enable-Migrations
按回車鍵后,會生成Migrations文件夾,以及Migrations文件夾下面的Configuration類和201711281316287_InitialCreate類:
Configuration:這個類允許你去配置如何遷移,對于本文將使用默認的配置(在本文中因為只有一個Context,Enable-Migrations將自動對context type作出適配);
201711281316287_InitialCreate:這個遷移之所以存在是因為我們之前用Code First創建了數據庫,在啟用遷移之前,scaffolded migration里面的代碼表示在數據庫中已經創建的對象,本文中即為表Students。
Code First Migrations有兩個需要熟悉的命令:
Add-Migration 將scaffold創建下一次基于上一次遷移以來的更改的遷移;
Update-Database 將任何掛起的遷移應用到數據庫;
以上面新增加的字段Grade屬性為例,命令Add-Migration允許我們對遷移進行命名,我們把遷移命名為AddGrade。
2、增加遷移節點
在程序包管理器控制臺中輸入命令:Add-Migration AddGrade
一個新的遷移(201711281402492_AddGrade)在目錄Migrations中創建成功:
201711281402492_AddGrade類結構如下:
namespace EF.FluentAPI.Migrations { using System; using System.Data.Entity.Migrations; public partial class AddGrade : DbMigration { public override void Up() { AddColumn("dbo.Students", "Grade", c => c.String(nullable: false, maxLength: 16, unicode: false)); } public override void Down() { DropColumn("dbo.Students", "Grade"); } } }
201711281402492_AddGrade的名稱是上面Add后面定義的遷移名稱,而類下面有兩個方法:一個是Up,一個是Down,記錄了需要升級的修改,這里也就是Students表增加了Grade列。只要我們在后面執行Update-Database,就會執行此類下面的Up函數。
這里的Down函數簡單介紹就是:為了回滾修改而設計的。如果用戶希望恢復到某一個遷移節點,程序會自動根據已經執行的遷移,判斷回滾哪些遷移,執行他們的Down函數。
3、更新數據庫
在程序包管理器控制臺中輸入命令:Update-Database -Verbose
查看數據庫,Students表已經增加Grade字段:
到此為止,遷移已經完成,再次運行項目:
查看數據庫:
輸入的數據保存到數據庫中。
四、修改屬性
1、將Student實體類中的Grade屬性的名稱修改為GradeTest:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EF.Model { public class Student { public int StudentID { get; set; } public string StudentName { get; set; } public int Age { get; set; } public string Sex { get; set; } // 將Grade屬性名修改為GradeTest public string GradeTest { get; set; } } }
2、增加遷移節點
在程序包管理器控制臺中輸入命令:Add-Migration ModifyGrade
在Migrations文件夾下面會生成本次的遷移記錄:201711290052153_ModifyGrade
查看201711290052153_ModifyGrade類結構:
namespace EF.FluentAPI.Migrations { using System; using System.Data.Entity.Migrations; public partial class ModifyGrade : DbMigration { public override void Up() { AddColumn("dbo.Students", "GradeTest", c => c.String(nullable: false, maxLength: 16, unicode: false)); DropColumn("dbo.Students", "Grade"); } public override void Down() { AddColumn("dbo.Students", "Grade", c => c.String(nullable: false, maxLength: 16, unicode: false)); DropColumn("dbo.Students", "GradeTest"); } } }
可以看到在Up方法里面,它不是直接修改了列的名稱,而是先增加了一個新列GradeTest,然后刪除舊列Grade。這樣執行會有一個后果:如果Grade列里面有數據,數據會全部丟失。
3、更新到數據庫
在程序包管理器控制臺中輸入命令:Update-Database -Verbose
查看數據庫表:
通過查看數據庫表,會發現新增加了GradeTest列,原先的Grade列被刪掉,數據也全部丟失。
五、刪除屬性
刪除屬性和增加屬性的操作差不多
1、修改Student實體類,注釋掉GradeTest屬性:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EF.Model { public class Student { public int StudentID { get; set; } public string StudentName { get; set; } public int Age { get; set; } public string Sex { get; set; } // 將GradeTest屬性刪除 //public string GradeTest { get; set; } } }
2、增加遷移節點
在程序包管理器控制臺中輸入命令:Add-Migration DeleteGradeTest
查看生成的遷移記錄類:
201711290130110_DeleteGradeTest類里面的Up方法里面刪除了GradeTest列。
3、更新到數據庫
在程序包管理器控制臺中輸入命令:Update-Database -Verbose
查看數據庫表,可以發現GradeTest列被刪除掉:
六、遷移至指定的版本(包括后退)
到目前為止,我們進行遷移都是進行升級,但是有些時候我們需要升級或降級至指定版本,例如我們想遷移數據庫至運行ModifyGrade遷移之后的狀態,此時我們就可以使用-TargetMigration來降級到這個版本。
在程序包管理器控制臺中輸入命令:Update-Database -TargetMigration:ModifyGrade
這個命令將會運行201711290130110_DeleteGradeTest類里面的Down命令。Reverting migrations表示回復遷移。
這時候在查看數據庫表,會發現Students表中又有了GradeTest列。
如果你想回滾一切至空數據庫,可以使用命令:Update-Database -TargetMigration:$InitialDatabase
這時候在查看數據庫,發現Students表中所有列都已經被刪除:
七、如何在保留現有數據的基礎上修改列名
查看DbMigration類,會發現該類下面有一個RenameColumn()的方法,使用該方法可以在不丟失數據的基礎上修改列的名稱:
1、修改Student實體類,將StudentName修改為Name。
2、在程序包管理器控制臺中輸入命令:Add-Migration RenameStudentName
,生成遷移文件,手動修改遷移類文件,修改內容如下:
namespace EF.FluentAPI.Migrations { using System; using System.Data.Entity.Migrations; public partial class RenameStudentName : DbMigration { public override void Up() { //AddColumn("dbo.Students", "Name", c => c.String(nullable: false, maxLength: 50)); AddColumn("dbo.Students", "GradeTest", c => c.String(nullable: false, maxLength: 16, unicode: false)); //DropColumn("dbo.Students", "StudentName"); RenameColumn("dbo.Students", "StudentName", "Name"); } public override void Down() { //AddColumn("dbo.Students", "StudentName", c => c.String(nullable: false, maxLength: 50)); DropColumn("dbo.Students", "GradeTest"); //DropColumn("dbo.Students", "Name"); RenameColumn("dbo.Students", "Name", "StudentName"); } } }
3、執行Update-Database命令,數據庫列名被自動修改。
這里值得注意的是:在執行Update命令時,程序會提醒操作者: Changing any part of an object name could break scripts and stored procedures。翻譯為中文:更改對象名的任一部分都可能會破壞腳本和存儲過程。及修改列名可能會導致存儲過程及其他調用列的sql腳本失效。
查看數據庫表發現列名已經修改:
注意:在實際開發中,不建議隨便修改列名:可能會導致其他用的該列的地方調用失敗。
總結:
1、遷移的關聯在數據庫的遷移歷史表__MigrationHistory和項目的Migrations文件夾下的繼承了DbMigration的cs文件。
2、Migrations文件夾下的繼承了DbMigration的cs文件可以手動修改,這里的修改可以非常靈活,表格和表格字段的增刪改,在這里都有。
代碼下載地址:點此下載
原文鏈接:https://www.cnblogs.com/dotnet261010/p/7912818.html
相關推薦
- 2022-05-19 C++實現簡單信息管理系統_C 語言
- 2022-07-21 pandas合并操作
- 2023-02-17 Go語言Gin處理響應方式詳解_Golang
- 2022-04-03 Android?App應用退到后臺顯示通知的實現方法_Android
- 2023-07-07 spring security權限路由匹配restful格式的詳情id設計
- 2022-07-08 C#中的Dialog對話框_C#教程
- 2022-06-27 在Python中如何讓字典保持有序_python
- 2022-10-03 使用useImperativeHandle時父組件第一次沒拿到子組件的問題_React
- 最近更新
-
- 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同步修改后的遠程分支