ASP.NET Core 3.1系列(16)——Entity Framework Core之Code First

news2024/11/25 12:54:28

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]

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

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数据表,可以看到NameAddress字段已经生成,其中Name字段最大长度为20Address字段最大长度为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

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

在这里插入图片描述

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; }
    }
}

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

在这里插入图片描述

定义AuthorBook,代码如下:

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; }
    }
}

AuthorConfigurationBookConfiguration需要继承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

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

在这里插入图片描述

5、结语

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/53000.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

操作系统02_进程管理_同步互斥信号量_PV操作_死锁---软考高级系统架构师007

存储管理可以分为固定存储管理和分页存储管理。 现在固定存储管理已经不用也不考,但要知道因为固定存储管理指的是整存整取 也就是把一整个程序,比如说10G的游戏全部都存到内存里 这样的话是非常占用内存的,这个固定存储管理现在已经不用了。 然后这里我们主要看分页存储管: …

网页去色变黑白+网页黑白恢复为彩色

前言 特定节日&#xff0c;你会发现网页和app首页都会变成灰色&#xff0c;以此来表达我们的哀思之情。 好奇宝宝想知道各个网站都是使用哪些小技巧来做出这种效果的&#xff08;由彩变灰&#xff0c;由灰变彩&#xff09;&#xff0c;于是稍微学习了一下… 由灰变彩 稍微想…

USDP集群服务器宕机后集群及组件重启

USDP集群的其中2服务器意外宕机&#xff0c;其中包括一台USDP管理服务节点主机和工作节点主机&#xff0c;服务器重新启动后&#xff0c;USDP智能大数据平台无法登录&#xff0c;启动UDSP服务&#xff08;/opt/usdp-srv/usdp/bin/start-udp-server.sh&#xff09;后可以登录&am…

Go1.9.3跑GinDemo

Gin 1. 简介 1.1. 介绍 Gin是一个golang的微框架&#xff0c;封装比较优雅&#xff0c;API友好&#xff0c;源码注释比较明确&#xff0c;具有快速灵活&#xff0c;容错方便等特点 对于golang而言&#xff0c;web框架的依赖要远比Python&#xff0c;Java之类的要小。自身的n…

Linux部署WordPress(宝塔版)

宝塔手册宝塔安装 yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh 宝塔配置 1.帮助命令&#xff1a;bt2.修改用户名(童心同萌)&#xff1a;bt 63.修改密码(123456)&#xff1a;bt 54.修改端口(888…

JWT详细介绍

文章目录1 jwt介绍1.1 什么是jwt1.2 使用场景1.2.1 授权1.2.2 信息交换1.3 JWT结构1.3.1 header1.3.2 payload1.3.3 signature 签名2 Python 实现2.1 手动编码2.2 jwt包3 校验 jwt5 js解析jwt1 jwt介绍 官网&#xff1a;https://jwt.io/ 本文以python来进行实战演示 1.1 什么…

KG-开源项目:CMeKG【利用自然语言处理与文本挖掘技术,基于大规模医学文本数据,以人机结合的方式研发的中文医学知识图谱】

CMeKG&#xff08;Chinese Medical Knowledge Graph&#xff09;是利用自然语言处理与文本挖掘技术&#xff0c;基于大规模医学文本数据&#xff0c;以人机结合的方式研发的中文医学知识图谱。 项目来源&#xff1a; 中文医学知识图谱CMeKG2.0版发布-自然语言处理实验室北京大…

iOS开发之打包上传到App Store——(一)各种证书的理解

OK&#xff0c;有日子没写iOS开发的相关文章啦&#xff0c;主要是最近的精力都没在这上面&#xff0c;不过既然产品已经快要出来了&#xff0c;就有必要了解一下各种证书啥的&#xff08;众所周知iOS的一堆证书可是很让人头大呀&#xff09;&#xff0c;最近确实被这个搞得头大…

外汇天眼:随着美元贬值所有世界货币,每个国家都在为自己着想

没有迹象表明各国政府愿意合作&#xff0c;各国被迫靠自己的力量建立防御措施&#xff0c;抵御万能的美元的无情力量。 在美联储的鹰派政策、美国经济强劲以及寻求市场波动避险的投资者的支持下&#xff0c;美元兑所有其他货币正在稳步走强&#xff0c;创下数十年来的最大涨幅。…

信号发生器不会用?一篇文章教会你

信号发生器是一种能提供各种频率、波形和输出电平电信号的设备。在测量各种电信系统或电信设备的振幅特性、频率特性、传输特性及其它电参数时&#xff0c;以及测量元器件的特性与参数时&#xff0c;用作测试的信号源或激励源。 1、信号发生器如何使用 选用与验电器相同电压等…

Gateway--服务网关

目录一、网关简介二、Gateway简介三、Gateway快速入门基础版增强版简写版四、Gateway核心架构基本概念执行流程五、断言内置路由断言工厂内置路由断言工厂的使用自定义路由断言工厂六、 过滤器局部过滤器内置局部过滤器内置局部过滤器的使用自定义局部过滤器全局过滤器内置全局…

ROS MoveIT2(humble)安装总结

版本 系统版本&#xff1a;ubuntu22.04 ROS2版本&#xff1a;humble Moveit版本&#xff1a;moveit2-humble 安装 ROS 2 和 Colcon 如果您在接下来的几个步骤中遇到错误&#xff0c;一个好的开始是返回并确保您已正确安装 ROS 2。用户通常忘记的一个是获取 ROS 2 安装本身。…

手写Redux(一):实现Redux

在React中&#xff0c;组件和组件之间通过props传递数据的规范&#xff0c;极大地增强了组件之间的耦合性&#xff0c;而context类似全局变量一样&#xff0c;里面的数据能被随意接触就能被随意修改&#xff0c;每个组件都能够改context里面的内容会导致程序的运行不可预料。 …

复习计算机网络——第二章记录(2)

理解一些基本概念&#xff1a; 1、数据&#xff08;data&#xff09;是运送信息的实体。 2、信号&#xff08;signal&#xff09;是数据的电气的或电磁的表现。 3、数据或信号可以是模拟的&#xff0c;也可以是数字的。 4、所谓“模拟的”就是连续变化的。 5、所谓“数字的…

后端微服务项目中出现的问题整理2022年11月

后端微服务项目中出现的问题整理2022年11月后端微服务项目中出现的问题整理2022年11月1.SpringBoot-Mail-Service&#xff08;Spring邮箱服务&#xff09;报错截图解决办法方法一&#xff1a;使用Resource注解方法二&#xff1a;添加(requiredfalse)Resource和Autowired区别2.反…

基于plc的自动洗碗机的设计(西门子)

目 录 摘 要 I Abstract II 1绪论 1 1.1全自动洗碗机的发展 1 1.2全自动洗碗机概述 2 1.2.1 全自动洗碗机的分类 2 1.2.2 全自动洗碗机的基本结构 3 1.2.3 全自动洗碗机的工作原理 4 1.3研究主要内容 4 2 全自动洗碗机机械设计 6 2.1 整体方案设计 6 2.2 各重要部件设计 6 2.2.…

TF-IDF

2.TF - IDF&#xff1a;作用&#xff1a;提取出来一句话中词的重要性&#xff0c;分成两个部分&#xff1a; tf: 词频(某一类中词条出现的次数 / 该类中所有词条数目) idf: 逆文档频率&#xff08;作用&#xff1a;去掉逗号&#xff0c;的等&#xff09;公式&#xff1a;idf l…

【第一阶段:java基础】第8章:面向对象编程高级-2(P394-P423)final、抽象类、接口、内部类

本系列博客是韩顺平老师java基础课的课程笔记&#xff0c;吐血推荐的一套全网最细java教程&#xff0c;获益匪浅 韩顺平java课程 目录&#xff08;P394-P423&#xff09; 1 final 2 抽象类 3 接口 4 内部类 1️⃣ 局部内部类 2️⃣&#x1f353;匿名内部类 3️⃣成员内部类 4️…

C++,顺序结构,选择结构,循环结构

目录 1.选择结构 1.1if语句 1.1.1单行if语句 1.1.2多行格式的if语句 1.1.3多条件if语句 1.1.4嵌套if语句 1.2三目运算符 1.3switch语句 2.循环结构 2.1while循环 2.2do..while语句 2.3for循环语句 2.4嵌套循环 3.跳转语句 3.1.1break 3.1.2continue 3.1.3goto语句 …

UDP-GlcNAc,UDPAG,尿苷二磷酸-N-乙酰基葡萄糖胺,UDP-N-乙酰葡糖胺

产品名称&#xff1a;UDP-GlcNAc 尿苷二磷酸-N-乙酰基葡萄糖胺&#xff0c;UDPAG&#xff0c;UDP-N-乙酰葡糖胺 别 名&#xff1a;5-二磷酸尿嘧啶核苷-N-乙酰半乳糖胺二钠盐;5′-二磷酸尿嘧啶核苷-N-乙酰半乳糖胺二钠盐 英文名&#xff1a;uridine 5-diphospho-N-acetyl-*g…