Entity?Framework實(shí)現(xiàn)數(shù)據(jù)遷移
一、合并和遷移
1、合并
合并是指“新的實(shí)體模型映射到數(shù)據(jù)庫中,更新其結(jié)構(gòu)”,例如:
新增了實(shí)體類,表現(xiàn)在數(shù)據(jù)庫中就是新增加實(shí)體類對(duì)應(yīng)的數(shù)據(jù)表。
刪除了實(shí)體類,表現(xiàn)在數(shù)據(jù)庫中就是刪除了實(shí)體類對(duì)應(yīng)的數(shù)據(jù)表。
在一個(gè)已經(jīng)存在的實(shí)體類中增加屬性,表現(xiàn)在數(shù)據(jù)庫中就是在實(shí)體類對(duì)應(yīng)的數(shù)據(jù)表中新增加字段。
在一個(gè)已經(jīng)存在的實(shí)體類中刪除屬性,表現(xiàn)在數(shù)據(jù)庫中就是在實(shí)體類對(duì)應(yīng)的數(shù)據(jù)表中刪除字段。
修改一個(gè)已經(jīng)存在的實(shí)體類中屬性的名稱或類型,表現(xiàn)在數(shù)據(jù)庫中就是修改實(shí)體類對(duì)應(yīng)的數(shù)據(jù)表中字段的名稱或類型。
2、遷移
遷移是指“在更新數(shù)據(jù)庫結(jié)構(gòu)時(shí),把老結(jié)構(gòu)中的數(shù)據(jù)遷移到新結(jié)構(gòu)中”。
二、遷移前的準(zhǔn)備工作
搭建項(xiàng)目結(jié)構(gòu),整體的項(xiàng)目結(jié)構(gòu)包括一個(gè)控制臺(tái)應(yīng)用程序和兩個(gè)類庫,項(xiàng)目結(jié)構(gòu)如下:
其中EF.Application是控制臺(tái)程序,EF.FluentAPI和EF.Model是類型,EF.Model里面存的是實(shí)體類,EF.FluentAPI是實(shí)體類的Map類,用來設(shè)置FluentAPI。
Student類結(jié)構(gòu)如下:
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類結(jié)構(gòu)如下:
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 { /// <summary> /// 使用FluentAPI配置 /// </summary> public class StudentMap :EntityTypeConfiguration<Student> { public StudentMap() { // 配置數(shù)據(jù)庫中生成的表的名稱 this.ToTable("Students"); // 設(shè)置StudentID列自動(dòng)增長 this.Property(p => p.StudentID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); // 設(shè)置StudentID列作為主鍵 this.HasKey(p => p.StudentID); // 設(shè)置StudentName列的類型是nvarchar,最大長度是50,必須的 this.Property(p => p.StudentName).HasColumnType("nvarchar").HasMaxLength(50).IsRequired(); // 設(shè)置Age列是必須的 this.Property(p => p.Age).IsRequired(); // 設(shè)置Sex的類型是nvarchar this.Property(p => p.Sex).HasColumnType("nvarchar").IsRequired(); } } }
EF上下文類結(jié)構(gòu):
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()); } } }
數(shù)據(jù)庫連接字符串:【注意:在EF.Application和EF.FluentAPI的App.config里面都要添加上該連接字符串】
<connectionStrings> <add name="CodeFirstApplication" connectionString="Server=.;Database=MigrationsDB;User Id=sa;Password=1qaz@WSX" providerName="System.Data.SqlClient"/> </connectionStrings>
控制臺(tái)程序:
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("請(qǐng)輸入學(xué)生姓名:"); string studentName = Console.ReadLine().Trim(); Console.WriteLine("請(qǐng)輸入學(xué)生年齡:"); int age = 0; if (!int.TryParse(Console.ReadLine().Trim(), out age)) { Console.WriteLine("年齡只能輸入正整數(shù),請(qǐng)重新輸入:"); return; } Console.WriteLine("請(qǐng)輸入學(xué)生性別(男/女):"); 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(); } } }
運(yùn)行程序:
查看數(shù)據(jù)庫:
其中生成的表__MigrationHistory用來記錄每次的遷移。
三、遷移
現(xiàn)在我們?cè)赟tudent實(shí)體類中增加Grade字段,整體項(xiàng)目做如下的改動(dòng):
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字段,用來實(shí)現(xiàn)數(shù)據(jù)遷移 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 { /// <summary> /// 使用FluentAPI配置 /// </summary> public class StudentMap :EntityTypeConfiguration<Student> { public StudentMap() { // 配置數(shù)據(jù)庫中生成的表的名稱 this.ToTable("Students"); // 設(shè)置StudentID列自動(dòng)增長 this.Property(p => p.StudentID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); // 設(shè)置StudentID列作為主鍵 this.HasKey(p => p.StudentID); // 設(shè)置StudentName列的類型是nvarchar,最大長度是50,必須的 this.Property(p => p.StudentName).HasColumnType("nvarchar").HasMaxLength(50).IsRequired(); // 設(shè)置Age列是必須的 this.Property(p => p.Age).IsRequired(); // 設(shè)置Sex的類型是nvarchar this.Property(p => p.Sex).HasColumnType("nvarchar").IsRequired(); // 設(shè)置Grade字段是必須的 this.Property(p => p.Grade).HasColumnType("varchar").HasMaxLength(16).IsRequired(); } } }
控制臺(tái):
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("請(qǐng)輸入學(xué)生姓名:"); string studentName = Console.ReadLine().Trim(); Console.WriteLine("請(qǐng)輸入學(xué)生年齡:"); int age = 0; if (!int.TryParse(Console.ReadLine().Trim(), out age)) { Console.WriteLine("年齡只能輸入正整數(shù),請(qǐng)重新輸入:"); return; } Console.WriteLine("請(qǐng)輸入學(xué)生性別(男/女):"); string sex = Console.ReadLine().Trim(); Console.WriteLine("請(qǐng)輸入年級(jí):"); 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(); } } }
啟用數(shù)據(jù)遷移:
1、打開遷移
在程序包管理器控制臺(tái)中輸入:Enable-Migrations
按回車鍵后,會(huì)生成Migrations文件夾,以及Migrations文件夾下面的Configuration類和201711281316287_InitialCreate類:
Configuration:這個(gè)類允許你去配置如何遷移,對(duì)于本文將使用默認(rèn)的配置(在本文中因?yàn)橹挥幸粋€(gè)Context,Enable-Migrations將自動(dòng)對(duì)context type作出適配);
201711281316287_InitialCreate:這個(gè)遷移之所以存在是因?yàn)槲覀冎坝肅ode First創(chuàng)建了數(shù)據(jù)庫,在啟用遷移之前,scaffolded migration里面的代碼表示在數(shù)據(jù)庫中已經(jīng)創(chuàng)建的對(duì)象,本文中即為表Students。
Code First Migrations有兩個(gè)需要熟悉的命令:
Add-Migration 將scaffold創(chuàng)建下一次基于上一次遷移以來的更改的遷移;
Update-Database 將任何掛起的遷移應(yīng)用到數(shù)據(jù)庫;
以上面新增加的字段Grade屬性為例,命令A(yù)dd-Migration允許我們對(duì)遷移進(jìn)行命名,我們把遷移命名為AddGrade。
2、增加遷移節(jié)點(diǎn)
在程序包管理器控制臺(tái)中輸入命令:Add-Migration AddGrade
一個(gè)新的遷移(201711281402492_AddGrade)在目錄Migrations中創(chuàng)建成功:
201711281402492_AddGrade類結(jié)構(gòu)如下:
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后面定義的遷移名稱,而類下面有兩個(gè)方法:一個(gè)是Up,一個(gè)是Down,記錄了需要升級(jí)的修改,這里也就是Students表增加了Grade列。只要我們?cè)诤竺鎴?zhí)行Update-Database,就會(huì)執(zhí)行此類下面的Up函數(shù)。
這里的Down函數(shù)簡單介紹就是:為了回滾修改而設(shè)計(jì)的。如果用戶希望恢復(fù)到某一個(gè)遷移節(jié)點(diǎn),程序會(huì)自動(dòng)根據(jù)已經(jīng)執(zhí)行的遷移,判斷回滾哪些遷移,執(zhí)行他們的Down函數(shù)。
3、更新數(shù)據(jù)庫
在程序包管理器控制臺(tái)中輸入命令:Update-Database -Verbose
查看數(shù)據(jù)庫,Students表已經(jīng)增加Grade字段:
到此為止,遷移已經(jīng)完成,再次運(yùn)行項(xiàng)目:
查看數(shù)據(jù)庫:
輸入的數(shù)據(jù)保存到數(shù)據(jù)庫中。
四、修改屬性
1、將Student實(shí)體類中的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、增加遷移節(jié)點(diǎn)
在程序包管理器控制臺(tái)中輸入命令:Add-Migration ModifyGrade
在Migrations文件夾下面會(huì)生成本次的遷移記錄:201711290052153_ModifyGrade
查看201711290052153_ModifyGrade類結(jié)構(gòu):
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方法里面,它不是直接修改了列的名稱,而是先增加了一個(gè)新列GradeTest,然后刪除舊列Grade。這樣執(zhí)行會(huì)有一個(gè)后果:如果Grade列里面有數(shù)據(jù),數(shù)據(jù)會(huì)全部丟失。
3、更新到數(shù)據(jù)庫
在程序包管理器控制臺(tái)中輸入命令:Update-Database -Verbose
查看數(shù)據(jù)庫表:
通過查看數(shù)據(jù)庫表,會(huì)發(fā)現(xiàn)新增加了GradeTest列,原先的Grade列被刪掉,數(shù)據(jù)也全部丟失。
五、刪除屬性
刪除屬性和增加屬性的操作差不多
1、修改Student實(shí)體類,注釋掉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、增加遷移節(jié)點(diǎn)
在程序包管理器控制臺(tái)中輸入命令:Add-Migration DeleteGradeTest
查看生成的遷移記錄類:
201711290130110_DeleteGradeTest類里面的Up方法里面刪除了GradeTest列。
3、更新到數(shù)據(jù)庫
在程序包管理器控制臺(tái)中輸入命令:Update-Database -Verbose
查看數(shù)據(jù)庫表,可以發(fā)現(xiàn)GradeTest列被刪除掉:
六、遷移至指定的版本(包括后退)
到目前為止,我們進(jìn)行遷移都是進(jìn)行升級(jí),但是有些時(shí)候我們需要升級(jí)或降級(jí)至指定版本,例如我們想遷移數(shù)據(jù)庫至運(yùn)行ModifyGrade遷移之后的狀態(tài),此時(shí)我們就可以使用-TargetMigration來降級(jí)到這個(gè)版本。
在程序包管理器控制臺(tái)中輸入命令:Update-Database -TargetMigration:ModifyGrade
這個(gè)命令將會(huì)運(yùn)行201711290130110_DeleteGradeTest類里面的Down命令。Reverting migrations表示回復(fù)遷移。
這時(shí)候在查看數(shù)據(jù)庫表,會(huì)發(fā)現(xiàn)Students表中又有了GradeTest列。
如果你想回滾一切至空數(shù)據(jù)庫,可以使用命令:Update-Database -TargetMigration:$InitialDatabase
這時(shí)候在查看數(shù)據(jù)庫,發(fā)現(xiàn)Students表中所有列都已經(jīng)被刪除:
七、如何在保留現(xiàn)有數(shù)據(jù)的基礎(chǔ)上修改列名
查看DbMigration類,會(huì)發(fā)現(xiàn)該類下面有一個(gè)RenameColumn()的方法,使用該方法可以在不丟失數(shù)據(jù)的基礎(chǔ)上修改列的名稱:
1、修改Student實(shí)體類,將StudentName修改為Name。
2、在程序包管理器控制臺(tái)中輸入命令:Add-Migration RenameStudentName
,生成遷移文件,手動(dòng)修改遷移類文件,修改內(nèi)容如下:
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、執(zhí)行Update-Database命令,數(shù)據(jù)庫列名被自動(dòng)修改。
這里值得注意的是:在執(zhí)行Update命令時(shí),程序會(huì)提醒操作者: Changing any part of an object name could break scripts and stored procedures。翻譯為中文:更改對(duì)象名的任一部分都可能會(huì)破壞腳本和存儲(chǔ)過程。及修改列名可能會(huì)導(dǎo)致存儲(chǔ)過程及其他調(diào)用列的sql腳本失效。
查看數(shù)據(jù)庫表發(fā)現(xiàn)列名已經(jīng)修改:
注意:在實(shí)際開發(fā)中,不建議隨便修改列名:可能會(huì)導(dǎo)致其他用的該列的地方調(diào)用失敗。
總結(jié):
1、遷移的關(guān)聯(lián)在數(shù)據(jù)庫的遷移歷史表__MigrationHistory和項(xiàng)目的Migrations文件夾下的繼承了DbMigration的cs文件。
2、Migrations文件夾下的繼承了DbMigration的cs文件可以手動(dòng)修改,這里的修改可以非常靈活,表格和表格字段的增刪改,在這里都有。
代碼下載地址:點(diǎn)此下載
到此這篇關(guān)于Entity Framework實(shí)現(xiàn)數(shù)據(jù)遷移的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Entity?Framework使用Fluent?API配置案例
- Entity?Framework使用配置伙伴創(chuàng)建數(shù)據(jù)庫
- Entity Framework使用DbModelBuilder API創(chuàng)建表結(jié)構(gòu)
- Entity Framework常用查詢語句
- Entity Framework中執(zhí)行sql語句
- Entity Framework系統(tǒng)架構(gòu)與原理介紹
- Entity?Framework?Core實(shí)現(xiàn)Like查詢?cè)斀?/a>
- Entity Framework Core批處理SQL語句
- Entity Framework Core實(shí)現(xiàn)軟刪除與查詢過濾器
- Entity Framework Core生成列并跟蹤列記錄
- Entity?Framework實(shí)體拆分多個(gè)表
相關(guān)文章
在SQL Server中使用CLR調(diào)用.NET方法實(shí)現(xiàn)思路
在.NET中新建一個(gè)類,并在這個(gè)類里新建一個(gè)方法,然后在SQL Server中調(diào)用這個(gè)方法,接下來我們將實(shí)現(xiàn)這個(gè)功能做了以下幾個(gè)步驟,詳細(xì)看下本文,感興趣的你可不要錯(cuò)過了哈2013-02-02記錄asp.net網(wǎng)站是什么原因?qū)е峦V惯\(yùn)行的代碼
這篇文章主要介紹了記錄asp.net網(wǎng)站是什么原因?qū)е峦V惯\(yùn)行的具體實(shí)現(xiàn)2014-03-03asp.net 使用Silverlight操作ASPNETDB數(shù)據(jù)庫
asp.net下使用Silverlight操作ASPNETDB數(shù)據(jù)庫的實(shí)現(xiàn)代碼2010-01-01wireshark抓取本地回環(huán)數(shù)據(jù)包和取出數(shù)據(jù)的方法
這篇文章主要介紹了wireshark抓取本地回環(huán)數(shù)據(jù)包和取出數(shù)據(jù)的方法,需要的朋友可以參考下2014-02-02ASP.net如何連接SQL SERVER 2012數(shù)據(jù)庫
這篇文章主要介紹了ASP.net連接SQL SERVER 2012數(shù)據(jù)庫的方法,非常不錯(cuò),在項(xiàng)目開發(fā)中經(jīng)??梢杂玫?,需要的朋友可以參考下2016-08-08