[转]ASP.NET Core 3.1系列(16)——EFCore之Code First
原文链接:ASP.NET Core 3.1系列(16)——EFCore之Code First
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<DaoDbContext> 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<Author>();
base.OnModelCreating(modelBuilder);
}
public virtual DbSet<Author> 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
{
/// <summary>
/// 主键
/// </summary>
[Key]
public int Id { get; set; }
}
}
在NuGet控制台中输入如下命令:
Add-Migration m1
然后更新数据库:
Update-Database
打开数据库查看新生成的Author数据表,可以看到主键字段Id已经生成,如下图所示:
3.2、定义文本长度——[StringLength]、[MinLength]、[MaxLength]#
在数据库中,部分字段的类型可能是varchar或nvarchar,此时可以通过[StringLength]、[MinLength]、[MaxLength]对其长度进行标识。在Author中新增Name和Address字段,代码如下:
using System.ComponentModel.DataAnnotations;
namespace App.Models
{
public class Author
{
/// <summary>
/// 主键
/// </summary>
[Key]
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
[MinLength(2)]
[MaxLength(20)]
public string Name { get; set; }
/// <summary>
/// 地址
/// </summary>
[StringLength(40)]
public string Address { get; set; }
}
}
在NuGet控制台中输入如下命令:
Add-Migration m2
然后更新数据库:
Update-Database
打开数据库查看新生成的Author数据表,可以看到Name和Address字段已经生成,其中Name字段最大长度为20,Address字段最大长度为40,如下图所示:
3.3、字段不能为NULL——[Required]#
在数据表中,主键不能为NULL。如果希望其他字段也不能为NULL,则可以使用[Required]进行标识,下面对Author进行修改,规定Name字段不能为空,代码如下:
using System.ComponentModel.DataAnnotations;
namespace App.Models
{
public class Author
{
/// <summary>
/// 主键
/// </summary>
[Key]
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
[Required]
[MinLength(2)]
[MaxLength(20)]
public string Name { get; set; }
/// <summary>
/// 地址
/// </summary>
[MinLength(5)]
[MaxLength(40)]
public string Address { get; set; }
}
}
在NuGet控制台中输入如下命令:
Add-Migration m3
然后更新数据库:
Update-Database
3.4、忽略映射字段——[NotMapped]#
在某些情况下,实体类中的部分字段并不需要在数据库中生成对应的字段,此时就可以使用[NotMapped]进行标识。下面对Author进行修改,添加一个Info字段,代码如下:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace App.Models
{
public class Author
{
/// <summary>
/// 主键
/// </summary>
[Key]
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
[Required]
[MinLength(2)]
[MaxLength(20)]
public string Name { get; set; }
/// <summary>
/// 地址
/// </summary>
[MinLength(5)]
[MaxLength(40)]
public string Address { get; set; }
/// <summary>
/// 信息
/// </summary>
[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
{
/// <summary>
/// 主键
/// </summary>
[Key]
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
[Required]
[MinLength(2)]
[MaxLength(20)]
[Column("Author_Name")]
public string Name { get; set; }
/// <summary>
/// 地址
/// </summary>
[MinLength(5)]
[MaxLength(40)]
[Column("Author_Address")]
public string Address { get; set; }
/// <summary>
/// 信息
/// </summary>
[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
{
/// <summary>
/// 主键
/// </summary>
[Key]
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
[Required]
[MinLength(2)]
[MaxLength(20)]
[Column("Author_Name")]
public string Name { get; set; }
/// <summary>
/// 地址
/// </summary>
[MinLength(5)]
[MaxLength(40)]
[Column("Author_Address")]
public string Address { get; set; }
/// <summary>
/// 信息
/// </summary>
[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
{
/// <summary>
/// 主键
/// </summary>
[Key]
public int Id { get; set; }
/// <summary>
/// 书名
/// </summary>
[StringLength(30)]
public string BookName { get; set; }
/// <summary>
/// 外键
/// </summary>
public int? AuthorId { get; set; }
/// <summary>
/// 导航属性
/// </summary>
[ForeignKey("AuthorId")]
public virtual Author Author { get; set; }
}
}
由于Author与Book是一对多的关系,因此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<Book>();
}
/// <summary>
/// 主键
/// </summary>
[Key]
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
[Required]
[MinLength(2)]
[MaxLength(20)]
public string Name { get; set; }
/// <summary>
/// 地址
/// </summary>
[MinLength(5)]
[MaxLength(40)]
public string Address { get; set; }
/// <summary>
/// 信息
/// </summary>
[NotMapped]
public string Info { get => $"姓名:{Name},地址:{Address}"; }
/// <summary>
/// 导航属性
/// </summary>
public virtual ICollection<Book> Book { get; set; }
}
}
最后更新一下DaoDbContext,代码如下:
using App.Models;
using Microsoft.EntityFrameworkCore;
namespace App.Context
{
public class DaoDbContext : DbContext
{
public DaoDbContext()
{
}
public DaoDbContext(DbContextOptions<DaoDbContext> 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<Author>();
modelBuilder.Entity<Book>();
base.OnModelCreating(modelBuilder);
}
public virtual DbSet<Author> Author { get; set; }
public virtual DbSet<Book> Book { get; set; }
}
}
在NuGet控制台中输入如下命令:
Add-Migration m7
然后更新数据库:
Update-Database
打开数据库,可以看到数据表Book已经生成,同时外键AuthorId也已经成功创建,如下图所示:
到此为止,我们已经熟悉了基本的Code First操作。其实Data Annotations中还包含很多其他的属性标识,如[Range]、[Comment]、[RegularExpression]等,有兴趣的同志可自行深入研究。
4、基于Fluent API的Code First#
上面介绍了基于Data Annotations的Code First,该模式主要是通过给实体类打标签定义数据表。在EF Core中,还有一种使用Fluent API定义数据表的方法,下面开始介绍其使用方法,项目结构如下图所示:
定义Author和Book,代码如下:
using System.Collections.Generic;
namespace App.Model
{
public class Author
{
public Author()
{
Book = new HashSet<Book>();
}
/// <summary>
/// 主键
/// </summary>
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 地址
/// </summary>
public string Address { get; set; }
/// <summary>
/// 导航属性
/// </summary>
public virtual ICollection<Book> Book { get; set; }
}
}
namespace App.Model
{
public class Book
{
/// <summary>
/// 主键
/// </summary>
public int Id { get; set; }
/// <summary>
/// 书名
/// </summary>
public string BookName { get; set; }
/// <summary>
/// 外键
/// </summary>
public int? AuthorId { get; set; }
/// <summary>
/// 导航属性
/// </summary>
public virtual Author Author { get; set; }
}
}
AuthorConfiguration和BookConfiguration需要继承IEntityTypeConfiguration<>接口,代码如下:
using App.Model;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace App.Config
{
public class AuthorConfiguration : IEntityTypeConfiguration<Author>
{
public void Configure(EntityTypeBuilder<Author> builder)
{
// 定义主键
builder.ToTable("Author").HasKey(p => p.Id);
// 定义字段Name
builder.Property(p => p.Name).IsRequired().HasMaxLength(20);
// 定义字段Address
builder.Property(p => p.Address).HasMaxLength(40);
}
}
}
using App.Model;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace App.Config
{
public class BookConfiguration : IEntityTypeConfiguration<Book>
{
public void Configure(EntityTypeBuilder<Book> builder)
{
// 定义主键
builder.ToTable("Book").HasKey(p => p.Id);
// 定义字段BookName
builder.Property(p => p.BookName).IsRequired().HasMaxLength(20);
// 定义外键AuthorId
builder.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<DaoDbContext> 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> Author { get; set; }
public virtual DbSet<Book> Book { get; set; }
}
}
在NuGet控制台中输入如下命令:
Add-Migration mig
然后更新数据库:
Update-Database
打开数据库,可以看到数据表Author和Book已经生成,同时外键AuthorId也已经成功创建,如下图所示:
5、结语#
本文主要介绍了EF Core中的Code First模式,在实际开发过程中更推荐使用Fluent API的方式,因为该方法耦合性较低且更加灵活。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!