五个常用的.NET数据库迁移框架

在.NET开发中,可以使用多种数据库迁移框架来帮助我们管理数据库模式的变更和版本控制。
以下是一些常用的.NET数据库迁移框架:
1、**Entity Framework Migrations**:Entity Framework是.NET的一个对象关系映射(ORM)框架,它提供了官方的迁移支持。通过使用Migrations,您可以自动化数据库模式的版本控制和更新,以与代码更改保持同步。
2、**DNXDB**:DNXDB是一个轻量级、开源的数据库迁移框架,支持多种数据库,包括SQL Server、MySQL和PostgreSQL等。它允许您通过使用简单的YAML文件来定义迁移脚本,并提供了自动化迁移和回滚的功能。
3、**FluentMigrator**:FluentMigrator是一个开源的数据库迁移框架,它提供了一种简单而流畅的语法来编写迁移脚本。它支持多种数据库,包括SQL Server、MySQL、PostgreSQL和SQLite等。
4、**MyBatis.NET**:MyBatis是Java中流行的ORM框架,但也有.NET版本。MyBatis.NET提供了类似于Entity Framework的迁移支持,但使用的是SQL脚本而不是代码迁移。
5、**SQL Server Management Studio (SSMS)**:虽然SSMS不是严格意义上的迁移框架,但它是一个强大的工具,可以帮助您管理和操作SQL Server数据库,包括数据库的备份、恢复、升级和迁移等操作。
这些框架各有优缺点,您可以根据自己的项目需求和技术背景选择适合您的框架。请注意,在选择框架之前,建议您仔细阅读文档、了解社区支持和社区反馈,以确保您选择了合适的工具。
优缺点:

Entity Framework Migrations:

优点:是.NET开发中常用的ORM框架,与代码的集成度高,可以自动跟踪和同步数据库模式的变更。

缺点:对于大型数据库和复杂查询,性能可能不如直接使用SQL。

DNXDB:

优点:轻量级、开源,支持多种数据库,可以通过简单的YAML文件来定义迁移脚本。

缺点:相对于其他框架,DNXDB的社区支持和文档可能不够丰富。

FluentMigrator:

优点:提供简单流畅的语法来编写迁移脚本,支持多种数据库。

缺点:对于复杂的大型数据库,性能可能不如直接使用SQL。

MyBatis.NET:

优点:类似于Java中的MyBatis框架,提供SQL脚本的迁移支持。

缺点:相对于其他框架,MyBatis.NET的社区支持和文档可能不够丰富。

SQL Server Management Studio (SSMS):

优点:是一个强大的SQL Server管理工具,可以帮助您管理和操作数据库,包括备份、恢复、升级和迁移等操作。

缺点:不是严格意义上的迁移框架,对于复杂的大型数据库,性能可能不如直接使用SQL。

下面讲解一下Entity Framework实现数据迁移的方法:

一、合并和迁移

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
{
    /// <summary>
    /// 使用FluentAPI配置
    /// </summary>
   public class StudentMap :EntityTypeConfiguration<Student>
    {
       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里面都要添加上该连接字符串】

<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("请输入学生姓名:");
            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
{
    /// <summary>
    /// 使用FluentAPI配置
    /// </summary>
   public class StudentMap :EntityTypeConfiguration<Student>
    {
       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文件可以手动修改,这里的修改可以非常灵活,表格和表格字段的增删改,在这里都有。

到此关于Entity Framework实现数据迁移的文章就介绍到这了,关注我,其他的四个框架会持续更新。希望对大家的学习有所帮助,感谢大家对CSharp精选营的支持。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在选择 .NET Core 数据库框架时,应根据项目需求、团队经验和数据库特性综合考虑。以下是几个受欢迎的 .NET Core 数据库框架: 1. Entity Framework Core(EF Core):EF Core 是官方推出的、跨数据库的 ORM 框架,可以与多种关系型数据库和 NoSQL 数据库集成。EF Core 提供了强大的对象关系映射功能,支持 LINQ 查询、数据库迁移和事务管理等功能。它易于使用、有广泛的文档和社区支持。 2. Dapper:Dapper 是一个简单、高性能的 ORM 框架,通过使用 SQL 查询语句和存储过程,提供对数据库的快速访问。Dapper 相对于 EF Core 更轻量级,对于对性能要求较高或需要手动编写 SQL 的场景更合适。它也有活跃的社区和丰富的文档。 3. NHibernate:NHibernate 是一个成熟且功能强大的 ORM 框架,提供了持久化对象和数据库之间的映射,支持多种数据库。NHibernate 提供了高级的功能,如缓存管理、延迟加载和乐观锁等。然而,相对于 EF Core 和 Dapper,它的学习曲线较陡,并且文档和社区支持相对较少。 综上所述,选择最适合的 .NET Core 数据库框架取决于项目需求和团队的熟悉程度。对于大部分应用程序来说,EF Core 是一种不错的选择,因为它提供了丰富的功能和易用性。如果项目对性能要求很高或需要手动编写 SQL,可以考虑使用 Dapper。而对于需要额外高级功能的项目,NHibernate 也是一个可选的方案。重要的是选择一个能够满足项目需求、简化开发并且有活跃的社区支持的框架
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值