欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Entity?Framework實(shí)現(xiàn)數(shù)據(jù)遷移

 更新時間:2022年03月04日 11:16:22   作者:.NET開發(fā)菜鳥  
本文詳細(xì)講解了Entity?Framework實(shí)現(xiàn)數(shù)據(jù)遷移的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下

一、合并和遷移

1、合并

合并是指“新的實(shí)體模型映射到數(shù)據(jù)庫中,更新其結(jié)構(gòu)”,例如:
新增了實(shí)體類,表現(xiàn)在數(shù)據(jù)庫中就是新增加實(shí)體類對應(yīng)的數(shù)據(jù)表。
刪除了實(shí)體類,表現(xiàn)在數(shù)據(jù)庫中就是刪除了實(shí)體類對應(yīng)的數(shù)據(jù)表。
在一個已經(jīng)存在的實(shí)體類中增加屬性,表現(xiàn)在數(shù)據(jù)庫中就是在實(shí)體類對應(yīng)的數(shù)據(jù)表中新增加字段。
在一個已經(jīng)存在的實(shí)體類中刪除屬性,表現(xiàn)在數(shù)據(jù)庫中就是在實(shí)體類對應(yīng)的數(shù)據(jù)表中刪除字段。
修改一個已經(jīng)存在的實(shí)體類中屬性的名稱或類型,表現(xiàn)在數(shù)據(jù)庫中就是修改實(shí)體類對應(yīng)的數(shù)據(jù)表中字段的名稱或類型。

2、遷移

遷移是指“在更新數(shù)據(jù)庫結(jié)構(gòu)時,把老結(jié)構(gòu)中的數(shù)據(jù)遷移到新結(jié)構(gòu)中”。

二、遷移前的準(zhǔn)備工作

搭建項目結(jié)構(gòu),整體的項目結(jié)構(gòu)包括一個控制臺應(yīng)用程序和兩個類庫,項目結(jié)構(gòu)如下:

其中EF.Application是控制臺程序,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列自動增長
           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>

控制臺程序:

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("請輸入學(xué)生姓名:");
            string studentName = Console.ReadLine().Trim();
            Console.WriteLine("請輸入學(xué)生年齡:");
            int age = 0;
            if (!int.TryParse(Console.ReadLine().Trim(), out age))
            {
                Console.WriteLine("年齡只能輸入正整數(shù),請重新輸入:");
                return;
            }
            Console.WriteLine("請輸入學(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)在我們在Student實(shí)體類中增加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字段,用來實(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列自動增長
           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();
       }
    }
}

控制臺:

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("請輸入學(xué)生姓名:");
            string studentName = Console.ReadLine().Trim();
            Console.WriteLine("請輸入學(xué)生年齡:");
            int age = 0;
            if (!int.TryParse(Console.ReadLine().Trim(), out age))
            {
                Console.WriteLine("年齡只能輸入正整數(shù),請重新輸入:");
                return;
            }
            Console.WriteLine("請輸入學(xué)生性別(男/女):");
            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();
        }
    }
}

啟用數(shù)據(jù)遷移:

1、打開遷移

在程序包管理器控制臺中輸入:Enable-Migrations

按回車鍵后,會生成Migrations文件夾,以及Migrations文件夾下面的Configuration類和201711281316287_InitialCreate類:

Configuration:這個類允許你去配置如何遷移,對于本文將使用默認(rèn)的配置(在本文中因?yàn)橹挥幸粋€Context,Enable-Migrations將自動對context type作出適配);

201711281316287_InitialCreate:這個遷移之所以存在是因?yàn)槲覀冎坝肅ode First創(chuàng)建了數(shù)據(jù)庫,在啟用遷移之前,scaffolded migration里面的代碼表示在數(shù)據(jù)庫中已經(jīng)創(chuàng)建的對象,本文中即為表Students。

Code First Migrations有兩個需要熟悉的命令:
Add-Migration 將scaffold創(chuàng)建下一次基于上一次遷移以來的更改的遷移;
Update-Database 將任何掛起的遷移應(yīng)用到數(shù)據(jù)庫;

以上面新增加的字段Grade屬性為例,命令A(yù)dd-Migration允許我們對遷移進(jìn)行命名,我們把遷移命名為AddGrade。

2、增加遷移節(jié)點(diǎn)

在程序包管理器控制臺中輸入命令:Add-Migration AddGrade

一個新的遷移(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后面定義的遷移名稱,而類下面有兩個方法:一個是Up,一個是Down,記錄了需要升級的修改,這里也就是Students表增加了Grade列。只要我們在后面執(zhí)行Update-Database,就會執(zhí)行此類下面的Up函數(shù)。

這里的Down函數(shù)簡單介紹就是:為了回滾修改而設(shè)計的。如果用戶希望恢復(fù)到某一個遷移節(jié)點(diǎn),程序會自動根據(jù)已經(jīng)執(zhí)行的遷移,判斷回滾哪些遷移,執(zhí)行他們的Down函數(shù)。

3、更新數(shù)據(jù)庫

在程序包管理器控制臺中輸入命令:Update-Database -Verbose

查看數(shù)據(jù)庫,Students表已經(jīng)增加Grade字段:

到此為止,遷移已經(jīng)完成,再次運(yùn)行項目:

查看數(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)

在程序包管理器控制臺中輸入命令:Add-Migration ModifyGrade

在Migrations文件夾下面會生成本次的遷移記錄: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方法里面,它不是直接修改了列的名稱,而是先增加了一個新列GradeTest,然后刪除舊列Grade。這樣執(zhí)行會有一個后果:如果Grade列里面有數(shù)據(jù),數(shù)據(jù)會全部丟失。

3、更新到數(shù)據(jù)庫

在程序包管理器控制臺中輸入命令:Update-Database -Verbose

查看數(shù)據(jù)庫表:

通過查看數(shù)據(jù)庫表,會發(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)

在程序包管理器控制臺中輸入命令:Add-Migration DeleteGradeTest

查看生成的遷移記錄類:

201711290130110_DeleteGradeTest類里面的Up方法里面刪除了GradeTest列。

3、更新到數(shù)據(jù)庫

在程序包管理器控制臺中輸入命令:Update-Database -Verbose

查看數(shù)據(jù)庫表,可以發(fā)現(xiàn)GradeTest列被刪除掉:

六、遷移至指定的版本(包括后退)

到目前為止,我們進(jìn)行遷移都是進(jìn)行升級,但是有些時候我們需要升級或降級至指定版本,例如我們想遷移數(shù)據(jù)庫至運(yùn)行ModifyGrade遷移之后的狀態(tài),此時我們就可以使用-TargetMigration來降級到這個版本。

在程序包管理器控制臺中輸入命令:Update-Database -TargetMigration:ModifyGrade

這個命令將會運(yùn)行201711290130110_DeleteGradeTest類里面的Down命令。Reverting migrations表示回復(fù)遷移。

這時候在查看數(shù)據(jù)庫表,會發(fā)現(xiàn)Students表中又有了GradeTest列。

如果你想回滾一切至空數(shù)據(jù)庫,可以使用命令:Update-Database -TargetMigration:$InitialDatabase

這時候在查看數(shù)據(jù)庫,發(fā)現(xiàn)Students表中所有列都已經(jīng)被刪除:

七、如何在保留現(xiàn)有數(shù)據(jù)的基礎(chǔ)上修改列名

查看DbMigration類,會發(fā)現(xiàn)該類下面有一個RenameColumn()的方法,使用該方法可以在不丟失數(shù)據(jù)的基礎(chǔ)上修改列的名稱:

1、修改Student實(shí)體類,將StudentName修改為Name。

2、在程序包管理器控制臺中輸入命令:Add-Migration RenameStudentName,生成遷移文件,手動修改遷移類文件,修改內(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ù)庫列名被自動修改。

這里值得注意的是:在執(zhí)行Update命令時,程序會提醒操作者: Changing any part of an object name could break scripts and stored procedures。翻譯為中文:更改對象名的任一部分都可能會破壞腳本和存儲過程。及修改列名可能會導(dǎo)致存儲過程及其他調(diào)用列的sql腳本失效。

查看數(shù)據(jù)庫表發(fā)現(xiàn)列名已經(jīng)修改:

注意:在實(shí)際開發(fā)中,不建議隨便修改列名:可能會導(dǎo)致其他用的該列的地方調(diào)用失敗。

總結(jié):

1、遷移的關(guān)聯(lián)在數(shù)據(jù)庫的遷移歷史表__MigrationHistory和項目的Migrations文件夾下的繼承了DbMigration的cs文件。

2、Migrations文件夾下的繼承了DbMigration的cs文件可以手動修改,這里的修改可以非常靈活,表格和表格字段的增刪改,在這里都有。

代碼下載地址:點(diǎn)此下載

到此這篇關(guān)于Entity Framework實(shí)現(xiàn)數(shù)據(jù)遷移的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論