从CRUD到高级功能:EF Core在.NET Core中全面应用(二)

目录

EFCore迁移深入

EFCore反向工程

EFCore实体关系

一对一关系

一对多关系

多对多关系

单向导航


EFCore迁移深入

在上文 地址 ,我们简单讲解了EFCore通过实体化类改变成一段脚本并将数据迁移到数据库当中,今天我们继续对迁移数据方面进行深入的学习了解,如下所示:

Migrations迁移:可以对当前连接的数据库执行编号更高的迁移,这个操作叫做"向上迁移(up)",也可以执行把数据库回退到旧的迁移,这个操作叫做"向下迁移(down)",除非有特殊需要否则不要删除Migrations文件夹下的代码。

比如说我们生成一个T_Persons表到数据库当中:

迁移数据库:当我们对我们的EFCore代码进行数据库迁移的时候,执行如下代码:

bash 复制代码
// init相当于git提交的日志记录的名称
add-migration init
// 更新到数据库
update-database

在终端执行完上述命令之后,会立刻生成一段初始化脚本,在脚本中就会有标识向上迁移和向下迁移的函数,如下所示:

然后我们在构建数据库的实体类当中新增一列,再执行迁移命令可以看到新生成的迁移脚本中就有向上和向下迁移的命令,方便我们进行修改,然后再执行update-database命令就可以生成到数据库当中了,如下所示:

升级/回滚版本:把数据库升级/回滚到xxx状态下,迁移脚本不动,可以执行如下命令进行:

bash 复制代码
update-database xxx

比如说我想回滚到初始的init版本,就执行 update-database init 命令即可,如下所示可以看到我们原本的Height列已经被删掉了,回到了我们初始的init状态:

删除迁移脚本:这里不建议手动去删除Migrations文件夹下的迁移脚本,容易将前后的逻辑关系搞坏掉,这里我们可以通过如下命令删除最后一次迁移脚本:

bash 复制代码
remove-migration

生成迁移代码:这里我们可以通过如下语句,生成迁移的SQL代码但不执行到数据库当中,但是对于update-database语句来说是直接生成到数据库当中,中间的SQL代码不会被展示出来,对于开发环境来讲我们一般使用update-database即可,但是对于生产环境(客户环境)中,一般是通过手动生成SQL代码的方式进行手动提交的:

bash 复制代码
script-migration

如果想执行init版本后添加AddHeight版本的SQL脚本的生成,我们需要通过如下语句进行生成SQL脚本而不是直接执行AddHeight:

bash 复制代码
script-migration init AddHeight

EFCore反向工程

反向工程:是指通过已有的数据库结构生成实体类和DbContext的过程,这是EFCore提供的一个重要功能,能够根据现有的数据库自动创建对应的代码模型以便开发者进行数据库操作和管理,对于数据库已经存在且无法修改或修改较少的情况下,反向工程是一个理想的选择。

接下来我们终端执行如下命令,来根据数据库已有表来反向生成实体类:

bash 复制代码
// 命令解读
// MySql数据库依赖包,如果是其他数据库就换成其他数据库依赖包名字
// Pomelo.EntityFrameworkCore.MySql 

// 实体类输出路径,如MyClassOpt
// -o 实体类输出路径,如MyClassOpt

// 使用 MySql 表、字段原名,不设置此参数的话,实体类名、属性名将会被复数化驼峰命名
// --use-database-names

// 指定表
// --table 表名称,指定表名称,可以指定单和多个表

// 将文件名复数化,字段名会以驼峰命名
--no-pluralize

// 例如
scaffold-dbcontext "server=localhost;port=3306;user=root;password=123456;database=mysql_test" Pomelo.EntityFrameworkCore.MySql -o Models

注意:生成的实体类可能不能满足项目的要求,可能需要手工修改或者增加配置,再次运行反向工程工具,对文件所做的任何更改都将丢失,所以不建议把反向工具当成了日常开发工具使用,不建议DBFirst。

EFCore实体关系

实体关系:在EFCore中指的是数据库中各个表之间的关联或关系,这些关系在EFCore中可以通过不同的方式定义和实现,主要的实体关系类型有三种:一对一关系、一对多关系和多对多关系,下面是这三种关系的简要说明:

一对一关系

在一对一关系中,每一条记录在一个表中都对应另一张表中的唯一记录,例如一个Order表和一个Delivery表,一个订单都有一个唯一的申请单,申请单也只能对应一个订单,如下所示:

关系配置: 一对一关系配置意味着,一个带一个,语句如下:

cs 复制代码
HasOne(...).WithOne(...);

然后我们再配置一下DbConent配置:

cs 复制代码
namespace test
{
    class MyDbContext : DbContext
    {
        public DbSet<Order> Orders { get; set; }
        public DbSet<Delivery> Deliveries { get; set; }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            base.OnConfiguring(optionsBuilder); // 加载基类配置
            // 配置数据库连接字符串
            optionsBuilder.UseMySQL("server=localhost;database=mysql_test;user=root;password=123456");
        }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder); // 加载基类配置
            // 从程序集自动加载配置类
            modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
        }
    }
}

执行迁移数据库命令之后,在入口文件插入几条数据测试一下,如下所示:

一对多关系

一对多关系是指一个表中的一条记录可以与另一个表中的多条记录相关联,常见的例子是一个articlet表和commient表,一篇文章有多个评论,如下所示:

关系配置: 一对多关系配置意味着,一个带多个,语句如下:

cs 复制代码
HasOne(...).WithMany(...);

当然反着在ArticleConfig配置类中进行配置也可以,如下所示:

然后我们再配置一下DbConent配置:

cs 复制代码
namespace test
{
    class MyDbContext : DbContext
    {
        public DbSet<Article> Articles { get; set; }
        public DbSet<Comment> Comments { get; set; }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            base.OnConfiguring(optionsBuilder); // 加载基类配置
            // 配置数据库连接字符串
            optionsBuilder.UseMySQL("server=localhost;database=mysql_test;user=root;password=123456");
        }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder); // 加载基类配置
            // 从程序集自动加载配置类
            modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
        }
    }
}

终端执行如下命令将实体类迁移到数据库当中:

cs 复制代码
add-migration init
update-database

然后我们在入口文件插入几条数据到数据库当中,如下可以看到我们一篇文章有多条评论了:

如果我们想查询一对多的关系,这里我们可以使用include进行关联查询,将关联的表的数据查询出来,如下所示:

多对多关系

多对多关系表示一个表中的多条记录可以与另一个表中的多条记录相关联。通常需要一个中间表来存储这种关系,例如学生和课程之间的关系,每个学生可以选修多门课程,每门课程也可以有多个学生,如下所示:

关系配置: 多对多关系配置意味着,多个带多个,语句如下:

cs 复制代码
HasMany(...).WithMany(...);

然后我们在入口文件插入几条数据到数据库当中,如下可以看到数据保存成功了:

如果想进行查询的话可以通过include拿到与课程关联的学生,并遍历该数据,如下所示:

单向导航

单向导航指的是在实体关系中,只有一方实体包含对另一方实体的引用,而另一方实体则没有对前者的引用,也就是说导航属性只存在于一方,另一方仅通过外键来关联而不持有对前者的导航属性,在配置的时候不设置反向的属性,WithMany()不设置参数即可:

接下来我们在配置类当中设置Leave实体类与User实体类是一对多关系,如下所示:

然后这里我们往数据库中插入一条数据,因为这里我们使用的是MySQL,由于外键约束的缘故所以这里的两个外键都要加上:

总结:对于主从结构的"一对多"表关系,一般是声明双向导航属性。而对于其他的"一对多"表关系:如果表属于被很多表引用的基础表,则用单向导航属性否则可以自由决定是否用双向导航属性。

相关推荐
yz-俞祥胜8 小时前
.Net Core Record 类型
servlet·.netcore
petunsecn1 天前
EFCore HasDefaultValueSql (续1 ValueGeneratedOnAdd)
c#·.netcore
张3蜂1 天前
Copilot 和 Windsurf哪个更适合于.netcore开发
.netcore·copilot
时光追逐者2 天前
C#/.NET/.NET Core技术前沿周刊 | 第 20 期(2025年1.1-1.5)
c#·.net·.netcore·微软技术
Libby博仙3 天前
.net core 为什么使用 null!
javascript·c#·asp.net·.netcore
csdn_aspnet3 天前
C# 或 .NetCore 如何使用 NPOI 导出图片到 Excel 文件
c#·excel·.netcore
是萝卜干呀3 天前
Backend - C# asp .net core
asp.net·.netcore·middleware·wwwroot·appsettings
时光追逐者4 天前
精选2款.NET开源的博客系统
开源·c#·.net·.netcore·微软技术
是萝卜干呀4 天前
Backend - C# asp .net core MVC
c#·mvc·.netcore