0 前言

本文正文第一节,会对 Code First 进行基本的介绍,以及对相关名词进行说明,读者一开始可以不用在这里消耗过多时间,可以先操作一遍例子,再回过头理解。

第二节,以一个简单的例子,展示 EF Core 的 Code First 模式的操作流程。

第三节,将 Code First 的其他指令例举出来,以便于日后翻查。

第四节(未完成),将 Code First 其他一些操作,如:在迁移代码中添加 SQL 语句等。

第五节,将 Code First 模式常见的问题列举出来,防止踩坑。

1 相关介绍

1.1 Code First 模式

以 EF Core 模型为准,使用迁移的方式,将 EF Core 模型的变化以增量的方式更新到数据库。

简单理解:以C#代码定义的数据实体,生成数据库的表结构。

1.2 相关名词

数据库上下文(DbContext):继承自 DbContext,主要作用是连接数据库,跟踪数据实体状态(实体状态包括:added、modified、deleted 等),将数据库实体的状态写入数据库(持久化至数据库中)。

数据实体(Entity):C#的实体类,与数据库的表对应

数据模型(Model):暂且认为是数据库的表吧(因为官方文档的描述,感觉就像是)

约定(conventions):主要是数据实体的类名、属性。

数据注释(data annotations):应用于类上、属性的特性(如:[Table("SysUser")]),会被 Fluent API 的配置覆盖。

Fluent API:于自定义的 DbContext 中重写 OnModelCreating 方法中,对数据模型描述的配置,如:

 protected override void OnModelCreating(ModelBuilder modelBuilder)
{
builder.Entity<User>().ToTable("SysUser");
}

数据实体(Entity)、数据模型(Model)、约定(conventions)、数据注释(data annotations)、Fluent API 说明:

数据实体(Entity)的类名、属性等,称之为约定(conventions),约定主要是为了定义数据模型(Model)的形状。

但是光靠约定可能不足以完整描述数据模型,有时我们的数据模型与我们的数据实体可能也有差异,这时,就可以通过数据注释(data annotations)和 Fluent API 补充。

2 EF Core 的基础使用

2.1 新建 WebApi 工程

这里基于 VS Code 工具,使用命令行创建一个 WebApi 程序:

mkdir CodeFirstTest & cd CodeFirstTest #新建文件夹DbFirstTest并切换至该目录下
dotnet new webapi --framework net6.0 #新建ASP.NET6.0 WebAPI程序

2.2 引入 EF Core 相关 Nuget 包

EF Core 部分 Nuget 包如下:

Microsoft.EntityFrameworkCore -->> 核心包
Microsoft.EntityFrameworkCore.Design -->> Design包:Code First 或 Db First 需要
Microsoft.EntityFrameworkCore.SqlServer -->> 微软官方 SQL Server 驱动
Pomelo.EntityFrameworkCore.MySql -->> 社区 MySql 驱动
MySql.EntityFrameworkCore -->> Oracle官方 MySql 驱动

其中核心包是必须的,另外还需配备对应数据库的驱动包,而 Design 包主要是在使用 Code First 或 Db First 需要的包。

这里,我们向工程引入必须的 Nuget 包,SQL 驱动程序选择 SQL Server 的:

dotnet add package Microsoft.EntityFrameworkCore --version 6.0.4
dotnet add package Microsoft.EntityFrameworkCore.Design --version 6.0.4
dotnet add package Microsoft.EntityFrameworkCore.SqlServer --version 6.0.4
# dotnet add package Pomelo.EntityFrameworkCore.MySql --version 6.0.1

2.3 准备配置信息

在 appsettings.json 中增加一个节点,用于连接数据库时使用。

"ConnectionStrings": {
"SqlServer": "server=localhost;database=efcore;uid=sa;pwd=Qwe123456;",
"MySql": "server=localhost;port=3306;database=efcore;user=root;password=123456;charset=utf8mb4;"
}

2.4 新建数据库上下文 DbContext

新建一个自定义的数据库上下文 TestDbContext:

using Microsoft.EntityFrameworkCore;

namespace CodeFirstTest;

public class TestContext : DbContext
{
public TestContext(DbContextOptions<TestContext> options) : base(options) { } protected override void OnConfiguring(DbContextOptionsBuilder options)
{
base.OnConfiguring(options);
} protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<User>();
base.OnModelCreating(builder);
} public virtual DbSet<User> User { get; set; }
}

2.5 创建数据实体

创建一个数据实体 User 如下:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore; namespace CodeFirstTest; [Table("SysUser")]
public class User
{
[Key]
public Guid Id { get; set; } = new Guid(); [StringLength(128)]
[Comment("姓名")]
public string? Name { get; set; } [StringLength(11)]
[Comment("手机号码")]
public string? Phone { get; set; }
}

[Table("SysUser")] 注释数据库中的表名为 SysUser。

[StringLength(128)] 注释字符串长度,[Comment("姓名")] 注释数据库中该字段含义。

这些注释,称为“数据注释”,主要是对数据模型的补充描述(可以简单认为:对数据库的表结构的补充描述)。

关于配置数据模型的详细内容,可以翻查EF Core官方文档:创建并配置模型

2.6 注册服务

在 Program.cs 中注册服务,并配置数据库连接串。

var configuration = builder.Configuration;
builder.Services.AddDbContext<TestContext>(options => {
options.UseSqlServer(configuration["ConnectionStrings:SqlServer"]);
});

2.7 编译项目

在生成迁移之前,需要先对工程进行编译,否则会报错。

dotnet build

2.8 数据库迁移(Code First 模式)

如果没有安装 EF 工具,需要先安装

# 安装全局工具
dotnet tool install --global dotnet-ef
# 更新工具
dotnet tool update --global dotnet-ef

创建一个名为 Initial 的迁移,将会在项目根目录下生成一个 Migrations 的目录:

dotnet ef migrations add Initial

更新到数据库

dotnet ef database update

2.9 增加测试控制器

增加一个 UserController 用于测试。

using Microsoft.AspNetCore.Mvc;

namespace CodeFirstTest.Controllers;

[ApiController]
[Route("[controller]")]
public class UserController : ControllerBase
{
private readonly TestContext _db; public UserController(TestContext db)
{
_db = db;
} [HttpGet]
public User? Get(Guid id)
{
return _db.User.Find(id);
} [HttpPost]
public void Post(User user)
{
_db.User.Add(user);
_db.SaveChanges();
} [HttpDelete]
public bool Delete(Guid id)
{
User? user = _db.User.Find(id) ?? null;
if (user == null) return false;
_db.User.Remove(user);
_db.SaveChanges();
return true;
}
}

2.10 运行项目

dotnet build
dotnet run

访问:https://localhost:7232/swagger/index.html

对接口进行操作,可以实现对 User 的增删查。

2.11 源码

Gitee:https://gitee.com/lisheng741/testnetcore/tree/master/EFCore/CodeFirstTest

Github:https://github.com/lisheng741/testnetcore/tree/master/EFCore/CodeFirstTest

3 数据库迁移

具体参考EF Core官方文档:管理数据库架构:迁移

3.1 安装工具

# 安装全局工具
dotnet tool install --global dotnet-ef # 更新工具
dotnet tool update --global dotnet-ef # 验证安装
dotnet ef

3.2 迁移

3.2.1 管理迁移

创建一个名为 Migrations 的目录,并生成一些文件

dotnet ef migrations add InitialCreate

创建迁移时指定迁移目录

dotnet ef migrations add InitialCreate --output-dir [directory]

删除迁移

dotnet ef migrations remove

列出所有迁移

dotnet ef migrations list

3.2.2 应用迁移

应用迁移主要有2种方式,一种是生成 SQL 脚本,一种是通过命令行工具执行命令进行迁移,具体请参考EF Core 官方文档:应用迁移

除了这两种迁移方式外,还有一种是在程序种迁移,即将迁移的代码写入程序中,由程序运行时触发。

1) 命令行工具

将迁移应用到数据库

dotnet ef database update

将迁移应用到数据库:指定迁移

dotnet ef database update AddNewTables

注意:使用该命令,也可以进行迁移回滚(回滚到之前的某个迁移)。

2) 生成 SQL 脚本
dotnet ef migrations script

指定迁移起点(From)

dotnet ef migrations script AddNewTables

指定迁移起点(From)和结束点(To)

dotnet ef migrations script AddNewTables AddAuditTable

幂等 SQL 脚本(idempotent):脚本将在内部检查已经应用哪些迁移(通过迁移历史记录表),并且只应用缺少的迁移。

dotnet ef migrations script --idempotent
3)在程序运行时进行迁移

请参考EF Core 文档:应用迁移:在运行时应用迁移

4 其他操作

4.1 迁移代码添加 SQL

请参考:EF Core 官方文档:管理迁移:添加原始 SQL

下面的例子,用一个新的 FullName 属性替换现有的 FirstNameLastName 属性,并将现存的数据转移到新的列上。

migrationBuilder.AddColumn<string>(
name: "FullName",
table: "Customer",
nullable: true); migrationBuilder.Sql("UPDATE Customer SET FullName = FirstName + ' ' + LastName;"); migrationBuilder.DropColumn(
name: "FirstName",
table: "Customer"); migrationBuilder.DropColumn(
name: "LastName",
table: "Customer");

4.2 自定义迁移操作

MigrationBuilder.Sql() 或 自定义 MigrationOperation 对象,可以对 MigrationBuilder 进行扩展。

如:想要在迁移代码中使用如下代码(CreateUser 方法为自定义方法)

migrationBuilder.CreateUser("SQLUser1", "Password");

4.2.1 使用 MigrationBuilder.Sql()

CreateUser 自定义代码如下:

public static OperationBuilder<SqlOperation> CreateUser(
this MigrationBuilder migrationBuilder,
string name,
string password)
=> migrationBuilder.Sql($"CREATE USER {name} WITH PASSWORD '{password}';");

4.2.2 自定义 MigrationOperation 对象

请参考EF Core 官方文档:自定义操作

创建和删除 API(EnsureCreated 和 EnsureDeleted)

在程序运行中可以调用的 API,用于管理数据库的创建和删除。

5 Code First 模式常见问题

5.1 列重命名

具体请查看EF Core 官方文档:管理迁移:列重命名

官方举的例子:如果你将属性从 Name 重命名为 FullName,EF Core 将生成以下迁移:

migrationBuilder.DropColumn(
name: "Name",
table: "Customers"); migrationBuilder.AddColumn<string>(
name: "FullName",
table: "Customers",
nullable: true);

该迁移代码将 Name 列删除,然后添加新的列 FullName,这样做,会导致 Name 列原有的数据丢失。

所以需要自行将该迁移代码修改如下:

migrationBuilder.RenameColumn(
name: "Name",
table: "Customers",
newName: "FullName");

参考来源

EF Core 官方文档

EF Core / 基础_从建库到增删改查

EF Core的基本使用

EF Core 的 Code First 模式的更多相关文章

  1. 基于EF Core的Code First模式的DotNetCore快速开发框架

    前言 最近接了几个小单子,因为是小单子,项目规模都比较小,业务相对来说,也比较简单.所以在选择架构的时候,考虑到效率方面的因素,就采取了asp.net+entity framework中的code f ...

  2. 【基于EF Core的Code First模式的DotNetCore快速开发框架】完成对DB First代码生成的支持

    前言 距离上一篇文章<基于EF Core的Code First模式的DotNetCore快速开发框架>已过去大半个年头,时光荏苒,岁月如梭...比较尴尬的是,在这大半个年头里,除了日常带娃 ...

  3. C# 嵌入dll 动软代码生成器基础使用 系统缓存全解析 .NET开发中的事务处理大比拼 C#之数据类型学习 【基于EF Core的Code First模式的DotNetCore快速开发框架】完成对DB First代码生成的支持 基于EF Core的Code First模式的DotNetCore快速开发框架 【懒人有道】在asp.net core中实现程序集注入

    C# 嵌入dll   在很多时候我们在生成C#exe文件时,如果在工程里调用了dll文件时,那么如果不加以处理的话在生成的exe文件运行时需要连同这个dll一起转移,相比于一个单独干净的exe,这种形 ...

  4. EF Core学习Code First

    下面通过实例来学习EF Core Code First,也就是通过EF Core迁移来完成从模型生成数据库. 本实例使用EntityFrameworkCore SQLite 数据库进行介绍,大家也可以 ...

  5. EF Core的Code First 基础

    一.创建实体类与映射类 通过NuGet引用Microsoft.EntityFrameworkCore 1.创建实体类 Code First可以通过为实体类字段添加相应特性,来创建对应的字段类型等,举例 ...

  6. EF 下的code fist 模式编程

    EF 分两种模式 codefirst(就是不知道数据是啥,也没有数据库)  和 database fist (数据已经设计好了) 首先打开vs  新建一个项目 创建一个控制台程序 然后 新建一个Tea ...

  7. NET Core 使用EF Core的Code First迁移和DBFirst

    DBFirst (1)Microsoft.EntityFrameworkCore (2)Microsoft.EntityFrameworkCore.Design (3)Microsoft.Entity ...

  8. EF core (code first) 通过自定义 Migration History 实现多租户使用同一数据库时更新数据库结构

    前言 写这篇文章的原因,其实由于我写EF core 实现多租户的时候,遇到的问题. 具体文章的链接: Asp.net core下利用EF core实现从数据实现多租户(1) Asp.net core下 ...

  9. EF core (code first) 通过自动迁移实现多租户数据分离 :按Schema分离数据

    前言 本文是多租户系列文章的附加操作文章,如果想查看系列中的其他文章请查看下列文章 主线文章 Asp.net core下利用EF core实现从数据实现多租户(1) Asp.net core下利用EF ...

随机推荐

  1. Linux 的目录结构是怎样的?

    这个问题,一般不会问.更多是实际使用时,需要知道.Linux 文件系统的结构层次鲜明,就像一棵倒立的树,最顶层是其根目录:Linux的目录结构常见目录说明: /bin:存放二进制可执行文件(ls,ca ...

  2. 使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?

    使用final关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的.例如,对于如下语句: final StringBuilder a=new StringBuilder ...

  3. jpg, jpeg和png区别?

    jpg是jpeg的缩写, 二者一致    PNG就是为取代GIF而生的, 无损压缩, 占用内存多    jpg牺牲图片质量, 有损, 占用内存小    PNG格式可编辑.如图片中有字体等,可利用PS再 ...

  4. Zookeeper 对节点的 watch监听通知是永久的吗?为什么 不是永久的?

    不是.官方声明:一个 Watch 事件是一个一次性的触发器,当被设置了 Watch 的数据发生了改变的时候,则服务器将这个改变发送给设置了 Watch 的客户端, 以便通知它们. 为什么不是永久的,举 ...

  5. Java如何声明变量?JS如何声明变量?

    Java采用强类型变量检查,像C语言一样.所有变量在编译之前必须声明,而且不能使用没有赋值的变量.例如:int x;x=1234;char y='F';其中X=1234说明是一个整数,Y='F'说明是 ...

  6. PowerDesigner生成MySQL脚本,表和字段进行转义

    打开Power Designer数据库建模工具,软件基本信息如下 如果PowerDesigner内置的(table_option)表物理操作没有,请看以下步骤 打开 Edit Current DBMS ...

  7. 使用 Spring 通过什么方式访问 Hibernate?

    在 Spring 中有两种方式访问 Hibernate:控制反转 Hibernate Template 和 Callback.继承 HibernateDAOSupport 提供一个 AOP 拦截器.

  8. 详解 IOC

    什么是IOC: IOC-Inversion Of Control,即"控制反转",不是什么技术,而是一种设计思想.在Java开发中,IOC意味着将你设计好的对象交给容器控制,而不是 ...

  9. 学习heartbeat-04 原理及部署

    1. Heartbeat介绍 1.1 Heartbeat作用 通过它可以将资源(IP及程序服务等资源)从一台故障计算机快速转移到另一台运转正常的机器继续提供服务,在实际生产应用场景中,heartbea ...

  10. 2018 百度web前端面试

    面试前 正式入职一年半左右,实习半年,勉强两年经验吧,然后很惊喜收到了百度的面试邀约,约得两点钟面试,然后本人一点钟就到了,通电话之后,面试官很热情,说正在吃饭吃完饭就去找我,让我去坐着等一会,然后一 ...