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. Ubuntu16.04 搭建samba服务器

    1昨天花了一天时间弄了NFS服务器,结果搭建完之后出现各种问题,要么挂载不上,要么就是字符乱码.今天在看到一个关于树莓派的介绍的时候,提到Samba服务器的搭建,我尝试了一下,结果发现很顺利地就能够正 ...

  2. Gradle Gretty进行runAppDebug的Listening for transport dt_socket at address: 5005 的后续配置

    出现 Listening for transport dt_socket at address: 5005:代表debug端口已启动好了,接下来你需要进行配置远程Debug,进行附加Debug进程: ...

  3. Java中8种基本数据类型是哪些

    1 public class Ceshi { 2 int a; 3 double b; 4 boolean c; 5 char d; 6 float f; 7 byte e; 8 long h; 9 ...

  4. nginx开启gzip和缓存配置

    # 开启gzip gzip on; # 启用gzip压缩的最小文件,小于设置值的文件将不会压缩 gzip_min_length 1k; # gzip 压缩级别,1-10,数字越大压缩的越好,也越占用C ...

  5. java中如何创建自定义异常Create Custom Exception

    9.创建自定义异常 Create Custom Exception 马克-to-win:我们可以创建自己的异常:checked或unchecked异常都可以, 规则如前面我们所介绍,反正如果是chec ...

  6. MongoDB从bson文件中恢复数据

    首先需要到mangodb的安装目录的bin下面找到mongorestore.exe WIN10系统MongoDB安装目录bin文件夹下没有mongorestore.exe 先下载工具  https:/ ...

  7. ubantu系统之 lunch时报错:no such file /....../.lunchrc

    no such file /....../.lunchrc 出现时: 使用 source build/envsetup.sh 执行完后 再用lunch

  8. 这道javascript 面试题 你必须会

    实现一个函数,运算结果可以满足如下预期结果: add(1)(2) // 3 add(1, 2, 3)(10) // 16 add(1)(2)(3)(4)(5) // 15 话不多说,实现如下: fun ...

  9. vs技巧 - 调试asp.net core源码

    学习asp.net core的方式除了看官方文档,看源码是也是一种很好的方式.本文介绍一种方法,简单配置vs,无需第三方插件就可以将asp.net core的源码链接自己的项目,随时穿梭于core的源 ...

  10. CommonsCollection6反序列化链学习

    CommonsCollection6 1.前置知识 1.1.HashSet HashSet 基于 HashMap 来实现的,是一个不允许有重复元素的集合.继承了序列化和集合 构造函数参数为空的话创建一 ...