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. mysql主从异步复制过程

    mysql是现在普遍使用的数据库,但是如果宕机了必然会造成数据丢失.为了保证mysql数据库的可靠性.就要会一些提高可靠性的技术. 主从复制原理如下. slave(从服务器) master(主服务器) ...

  2. 模糊查询like语句该怎么写?

    第1种:在Java代码中添加sql通配符. string wildcardname = "%smi%"; list<name> names = mapper.selec ...

  3. Thread 类的 sleep()方法和对象的 wait()方法都可以让线 程暂停执行,它们有什么区别?

    sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程 暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保 持,因此休眠时间结束后会自动恢复(线程回 ...

  4. Java 线程数过多会造成什么异常?

    1.线程的生命周期开销非常高 2.消耗过多的 CPU 资源 如果可运行的线程数量多于可用处理器的数量,那么有线程将会被闲置.大量空 闲的线程会占用许多内存,给垃圾回收器带来压力,而且大量的线程在竞争  ...

  5. java中的方法覆盖(Overriding)和方法重载(Overloading)是什么意思?重写跟重载的区别?

    java中的方法重载发生在同一个类里面两个或者多个方法的方法名相同但是参数不同的情况.与此相对,方法覆盖是说子类重新定义了父类的方法.方法覆盖必须有相同的方法名,参数列表和返回类型. 覆盖者可能不会限 ...

  6. BMZCTF ssrfme

    <?php if(isset($_GET) && !empty($_GET)){ $url = $_GET['file']; $path = "upload/" ...

  7. Linux编程 | 使用 make

    目录 简单的 makefile 文件 常规的 makefile 文件 常用参数 make 内置规则 后缀和模式规则 make 管理函数库 在Linux 环境中,make 是一个非常重要的编译命令.不管 ...

  8. Numpy非常重要有用的数组合并操作

    Numpy非常重要有用的数组合并操作 背景:在给机器学习准备数据的过程中,经常需要进行不同来源的数据合并的操作. 两类场景: 给已有的数据添加多行,比如增添一些样本数据进去: 给已有的数据添加多列,比 ...

  9. css3 弹性布局和多列布局

    弹性盒子基础 弹性盒子(Flexible Box)是css3中盒子模型的弹性布局,在传统的布局方式上增加了很多灵活性. 定义一个弹性盒子 在父盒子上定义display属性: #box{ display ...

  10. react开发教程(三)组件的构建

    什么是组件 组件化就好像我们的电脑装机一样,一个电脑由显示器.主板.内存.显卡.硬盘,键盘,鼠标.... 组件化开发有如下的好处:降低整个系统的耦合度,在保持接口不变的情况下,我们可以替换不同的组件快 ...