ASP.NET Core 3.1系列(16)——Entity Framework Core之Code First
创始人
2024-03-09 04:33:53
0

1、前言

前一篇博客介绍了EFCore中的DB First开发模式,该模式可以根据数据库生成实体类和数据库上下文,因此适用于数据库已经存在的场景。而与之相对应的,Code First主要是根据自定义的实体类和数据库上下文反向构建数据库,因此也可以看做是DB First的逆过程,下面开始介绍。

2、定义实体类和数据库上下文

新建一个Web API项目,使用NuGet引入如下组件:

Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore.Tools

新建实体类Author、数据库上下文DaoDbContext,如下图所示:

在这里插入图片描述
DaoDbContext的代码如下所示:

using App.Models;
using Microsoft.EntityFrameworkCore;namespace App.Context
{public class DaoDbContext : DbContext{public DaoDbContext(){}public DaoDbContext(DbContextOptions options) : base(options){}protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder){optionsBuilder.UseSqlServer("Data Source=DSF-PC;Initial Catalog=Dao;User ID=sa;Password=123456;");}protected override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.Entity();base.OnModelCreating(modelBuilder);}public virtual DbSet Author { get; set; }}
}

Author先不用添加代码:

namespace App.Models
{public class Author{}
}

3、基于Data Annotations的Code First

3.1、定义主键——[Key]

Code First模式通过实体类生成数据表,而数据表必然含有一个主键,在Code First中可以使用[Key]来标识实体类中的主键字段,代码如下:

using System.ComponentModel.DataAnnotations;namespace App.Models
{public class Author{/// /// 主键/// [Key]public int Id { get; set; }}
}

NuGet控制台中输入如下命令:

Add-Migration m1

然后更新数据库:

Update-Database

打开数据库查看新生成的Author数据表,可以看到主键字段Id已经生成,如下图所示:

在这里插入图片描述

3.2、定义文本长度——[StringLength]、[MinLength]、[MaxLength]

在数据库中,部分字段的类型可能是varcharnvarchar,此时可以通过[StringLength][MinLength][MaxLength]对其长度进行标识。在Author中新增NameAddress字段,代码如下:

using System.ComponentModel.DataAnnotations;namespace App.Models
{public class Author{/// /// 主键/// [Key]public int Id { get; set; }/// /// 姓名/// [MinLength(2)][MaxLength(20)]public string Name { get; set; }/// /// 地址/// [StringLength(40)]public string Address { get; set; }}
}

NuGet控制台中输入如下命令:

Add-Migration m2

然后更新数据库:

Update-Database

打开数据库查看新生成的Author数据表,可以看到NameAddress字段已经生成,其中Name字段最大长度为20Address字段最大长度为40,如下图所示:

在这里插入图片描述

3.3、字段不能为NULL——[Required]

在数据表中,主键不能为NULL。如果希望其他字段也不能为NULL,则可以使用[Required]进行标识,下面对Author进行修改,规定Name字段不能为空,代码如下:

using System.ComponentModel.DataAnnotations;namespace App.Models
{public class Author{/// /// 主键/// [Key]public int Id { get; set; }/// /// 姓名/// [Required][MinLength(2)][MaxLength(20)]public string Name { get; set; }/// /// 地址/// [MinLength(5)][MaxLength(40)]public string Address { get; set; }}
}

NuGet控制台中输入如下命令:

Add-Migration m3

然后更新数据库:

Update-Database

打开数据库查看新生成的Author数据表,可以看到Name被定义为不能为NULL,如下图所示:

在这里插入图片描述

3.4、忽略映射字段——[NotMapped]

在某些情况下,实体类中的部分字段并不需要在数据库中生成对应的字段,此时就可以使用[NotMapped]进行标识。下面对Author进行修改,添加一个Info字段,代码如下:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;namespace App.Models
{public class Author{/// /// 主键/// [Key]public int Id { get; set; }/// /// 姓名/// [Required][MinLength(2)][MaxLength(20)]public string Name { get; set; }/// /// 地址/// [MinLength(5)][MaxLength(40)]public string Address { get; set; }/// /// 信息/// [NotMapped]public string Info { get => $"姓名:{Name},地址:{Address}"; }}
}

NuGet控制台中输入如下命令:

Add-Migration m4

然后更新数据库:

Update-Database

打开数据库查看新生成的Author数据表,可以看到实体类中的Info字段并没有创建对应的字段,如下图所示:

在这里插入图片描述

3.5、定义列名——[Column]

在某些情况下,我们希望手动设置某个字段在数据表中对应的列名,此时就可以使用[Column]进行标识,下面对Author进行修改,给每个字段加上前缀Author_,代码如下:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;namespace App.Models
{public class Author{/// /// 主键/// [Key]public int Id { get; set; }/// /// 姓名/// [Required][MinLength(2)][MaxLength(20)][Column("Author_Name")]public string Name { get; set; }/// /// 地址/// [MinLength(5)][MaxLength(40)][Column("Author_Address")]public string Address { get; set; }/// /// 信息/// [NotMapped]public string Info { get => $"姓名:{Name},地址:{Address}"; }}
}

NuGet控制台中输入如下命令:

Add-Migration m5

然后更新数据库:

Update-Database

打开数据库查看新生成的Author数据表,可以看到数据表中的字段已经加上了Author_前缀,如下图所示:

在这里插入图片描述

3.6、定义表名——[Table]

如果希望手动设置数据表名称,则可以使用[Table]进行标识,下面对Author进行修改,将表名设置为T_AuthorInfo,代码如下:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;namespace App.Models
{[Table("T_AuthorInfo")]public class Author{/// /// 主键/// [Key]public int Id { get; set; }/// /// 姓名/// [Required][MinLength(2)][MaxLength(20)][Column("Author_Name")]public string Name { get; set; }/// /// 地址/// [MinLength(5)][MaxLength(40)][Column("Author_Address")]public string Address { get; set; }/// /// 信息/// [NotMapped]public string Info { get => $"姓名:{Name},地址:{Address}"; }}
}

NuGet控制台中输入如下命令:

Add-Migration m6

然后更新数据库:

Update-Database

打开数据库查看新生成的Author数据表,可以看到数据表的名称已经修改为T_AuthorInfo,如下图所示:

在这里插入图片描述

3.7、定义外键——[ForeignKey]

如果存在一对多的情况,则可以使用[ForeignKey]对外键进行标识。新建一个实体类Book,该类包含一个外键AuthorId,代码如下:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;namespace App.Models
{public class Book{/// /// 主键/// [Key]public int Id { get; set; }/// /// 书名/// [StringLength(30)]public string BookName { get; set; }/// /// 外键/// public int? AuthorId { get; set; }/// /// 导航属性/// [ForeignKey("AuthorId")]public virtual Author Author { get; set; }}
}

由于AuthorBook是一对多的关系,因此Author中需要定义一个Book集合,代码如下:

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;namespace App.Models
{public class Author{public Author(){Book = new HashSet();}/// /// 主键/// [Key]public int Id { get; set; }/// /// 姓名/// [Required][MinLength(2)][MaxLength(20)]public string Name { get; set; }/// /// 地址/// [MinLength(5)][MaxLength(40)]public string Address { get; set; }/// /// 信息/// [NotMapped]public string Info { get => $"姓名:{Name},地址:{Address}"; }/// /// 导航属性/// public virtual ICollection Book { get; set; }}
}

最后更新一下DaoDbContext,代码如下:

using App.Models;
using Microsoft.EntityFrameworkCore;namespace App.Context
{public class DaoDbContext : DbContext{public DaoDbContext(){}public DaoDbContext(DbContextOptions options) : base(options){}protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder){optionsBuilder.UseSqlServer("Data Source=10.8.59.253;Initial Catalog=Dao;uid=sa;pwd=gis1a6b7c!Z;");}protected override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.Entity();modelBuilder.Entity();base.OnModelCreating(modelBuilder);}public virtual DbSet Author { get; set; }public virtual DbSet Book { get; set; }}
}

NuGet控制台中输入如下命令:

Add-Migration m7

然后更新数据库:

Update-Database

打开数据库,可以看到数据表Book已经生成,同时外键AuthorId也已经成功创建,如下图所示:

在这里插入图片描述
到此为止,我们已经熟悉了基本的Code First操作。其实Data Annotations中还包含很多其他的属性标识,如[Range][Comment][RegularExpression]等,有兴趣的同志可自行深入研究。

4、基于Fluent API的Code First

上面介绍了基于Data AnnotationsCode First,该模式主要是通过给实体类打标签定义数据表。在EF Core中,还有一种使用Fluent API定义数据表的方法,下面开始介绍其使用方法,项目结构如下图所示:

在这里插入图片描述

定义AuthorBook,代码如下:

using System.Collections.Generic;namespace App.Model
{public class Author{public Author(){Book = new HashSet();}/// /// 主键/// public int Id { get; set; }/// /// 姓名/// public string Name { get; set; }/// /// 地址/// public string Address { get; set; }/// /// 导航属性/// public virtual ICollection Book { get; set; }}
}
namespace App.Model
{public class Book{/// /// 主键/// public int Id { get; set; }/// /// 书名/// public string BookName { get; set; }/// /// 外键/// public int? AuthorId { get; set; }/// /// 导航属性/// public virtual Author Author { get; set; }}
}

AuthorConfigurationBookConfiguration需要继承IEntityTypeConfiguration<>接口,代码如下:

using App.Model;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;namespace App.Config
{public class AuthorConfiguration : IEntityTypeConfiguration{public void Configure(EntityTypeBuilder builder){// 定义主键builder.ToTable("Author").HasKey(p => p.Id);// 定义字段Namebuilder.Property(p => p.Name).IsRequired().HasMaxLength(20);// 定义字段Addressbuilder.Property(p => p.Address).HasMaxLength(40);}}
}
using App.Model;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;namespace App.Config
{public class BookConfiguration : IEntityTypeConfiguration{public void Configure(EntityTypeBuilder builder){// 定义主键builder.ToTable("Book").HasKey(p => p.Id);// 定义字段BookNamebuilder.Property(p => p.BookName).IsRequired().HasMaxLength(20);// 定义外键AuthorIdbuilder.HasOne(p => p.Author).WithMany(p => p.Book).HasForeignKey(p => p.AuthorId).OnDelete(DeleteBehavior.Cascade).HasConstraintName("FK_Book_Author");}}
}

最后添加DaoDbContext部分,代码如下:

using App.Config;
using App.Model;
using Microsoft.EntityFrameworkCore;namespace App.Context
{public class DaoDbContext : DbContext{public DaoDbContext(){}public DaoDbContext(DbContextOptions options) : base(options){}protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder){optionsBuilder.UseSqlServer("Data Source=DSF-PC;Initial Catalog=Dao;User ID=sa;Password=123456;");}protected override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.ApplyConfiguration(new AuthorConfiguration());modelBuilder.ApplyConfiguration(new BookConfiguration());base.OnModelCreating(modelBuilder);}public virtual DbSet Author { get; set; }public virtual DbSet Book { get; set; }}
}

NuGet控制台中输入如下命令:

Add-Migration mig

然后更新数据库:

Update-Database

打开数据库,可以看到数据表AuthorBook已经生成,同时外键AuthorId也已经成功创建,如下图所示:

在这里插入图片描述

5、结语

本文主要介绍了EF Core中的Code First模式,在实际开发过程中更推荐使用Fluent API的方式,因为该方法耦合性较低且更加灵活。

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
群晖外网访问终极解决方法:IP... 写在前面的话 受够了群晖的quickconnet的小水管了,急需一个新的解决方法&#x...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
Azure构建流程(Power... 这可能是由于配置错误导致的问题。请检查构建流程任务中的“发布构建制品”步骤,确保正确配置了“Arti...