夜猫子的知识栈 夜猫子的知识栈
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

夜猫子

前端练习生
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Node基础

  • 《MySQL》学习笔记

  • Midway

  • Nest

    • 开篇词
    • 学习理由
    • nest概念扫盲
    • 快速掌握 nestcli
    • 5种http数据传输方式
    • IoC 解决了什么痛点问题?
    • 如何调试 Nest 项目
    • Provider注入对象
    • 全局模块和生命周期
    • AOP 架构有什么好处?
    • 一网打尽 Nest 全部装饰器
    • Nest如何自定义装饰器
    • Metadata和Reflector
    • ExecutionContext切换上下文
    • Module和Provider的循环依赖处理
    • 如何创建动态模块
    • Nest和Express,fastify
    • Nest的Middleware
    • RxJS和Interceptor
    • 内置Pipe和自定义Pipe
    • ValidationPipe验证post请求参数
    • 如何自定义 Exception Filter
    • 图解串一串 Nest 核心概念
    • 接口如何实现多版本共存
    • Express如何使用multer实现文件上传
    • Nest使用multer实现文件上传
    • 图书管理系统
    • 大文件分片上传
    • 最完美的 OSS 上传方案
    • Nest里如何打印日志
    • 为什么Node里要用Winston打印日志
    • Nest 集成日志框架 Winston
    • 通过Desktop学Docker也太简单了
    • 你的第一个 Dockerfile
    • Nest 项目如何编写 Dockerfile
    • 提升 Dockerfile 水平的 5 个技巧
    • Docker 是怎么实现的
    • 为什么 Node 应用要用 PM2 来跑?
    • 快速入门 MySQL
    • SQL 查询语句的所有语法和函数
    • 一对一、join 查询、级联方式
    • 一对多、多对多关系的表设计
    • 子查询和 EXISTS
    • SQL 综合练习
    • MySQL 的事务和隔离级别
    • MySQL 的视图、存储过程和函数
    • Node 操作 MySQL 的两种方式
    • 快速掌握 TypeORM
      • 新建一个 TypeORM 项目:
      • 我们分别来过一遍这些配置:
      • 而创建表的依据就是 Entity:
      • 表创建好了,接下来就是增删改查了。
      • 那如果想批量插入和修改呢?
      • 删除和批量删除用 delete 方法:
      • 此外,你还可以用 findAndCount 来拿到有多少条记录:
      • findOneOrFail 或者 findOneByOrFail,如果没找到,会抛一个 EntityNotFoundError 的异常:
      • 此外,你还可以用 query 方法直接执行 sql 语句:
      • 但复杂 sql 语句不会直接写,而是会用 query builder:
      • 有没有什么简便方法呢?
      • 总结
        • 我们过了一遍 TypeORM 的各种概念,画个图总结下:
        • 具体的 EntityManager 和 Repository 的方法有这些:
    • TypeORM 一对一的映射和关联 CRUD
    • TypeORM 一对多的映射和关联 CRUD
    • TypeORM 多对多的映射和关联 CRUD
    • 在 Nest 里集成 TypeORM
    • TypeORM保存任意层级的关系
    • 生产环境为什么用TypeORM的migration迁移功能
    • Nest 项目里如何使用 TypeORM 迁移
    • 如何动态读取不同环境的配置?
    • 快速入门 Redis
    • 在 Nest 里操作 Redis
    • 为什么不用 cache-manager 操作 Redis
    • 两种登录状态保存方式:JWT、Session
    • Nest 里实现 Session 和 JWT
    • MySQL + TypeORM + JWT 实现登录注册
    • 基于 ACL 实现权限控制
    • 基于 RBAC 实现权限控制
    • access_token和refresh_token实现无感登录
    • 单token无限续期实现登录无感刷新
    • 使用 passport 做身份认证
    • passport 实现 GitHub 三方账号登录
    • passport 实现 Google 三方账号登录
    • 为什么要使用 Docker Compose ?
    • Docker 容器通信的最简单方式:桥接网络
    • Docker 支持重启策略,是否还需要 PM2
    • 快速掌握 Nginx 的 2 大核心用法
    • 基于 Nginx 实现灰度系统
    • 基于 Redis 实现分布式 session
    • Redis + 高德地图,实现附近的充电宝
    • 用 Swagger 自动生成 api 文档
    • 如何灵活创建 DTO
    • class- validator 的内置装饰器,如何自定义装饰器
    • 序列化 Entity,你不需要 VO 对象
    • 手写序列化 Entity 的拦截器
    • 使用 compodoc 生成文档
    • Node 如何发邮件?
    • 实现基于邮箱验证码的登录
    • 基于 sharp 实现 gif 压缩工具
    • 大文件如何实现流式下载?
    • Puppeteer 实现爬虫,爬取 BOSS 直聘全部前端岗位
    • 实现扫二维码登录
    • Nest 的 REPL 模式
    • 实现 Excel 导入导出
    • 如何用代码动态生成 PPT
    • 如何拿到服务器 CPU、内存、磁盘状态
    • Nest 如何实现国际化?
    • 会议室预订系统:需求分析和原型图
    • 会议室预订系统:技术方案和数据库设计
    • 会议室预订系统:用户管理模块--用户注册
    • 会议室预订系统:用户管理模块--配置抽离、登录认证鉴权
    • 会议室预订系统:用户管理模块-- interceptor、修改信息接口
    • 会议室预订系统:用户管理模块--用户列表和分页查询
    • 会议室预订系统:用户管理模块-- swagger 接口文档
    • 会议室预订系统:用户管理模块-- 用户端登录注册页面
    • 会议室预订系统:用户管理模块-- 用户端信息修改页面
    • 会议室预订系统:用户管理模块-- 头像上传
    • 会议室预订系统:用户管理模块-- 管理端用户列表页面
    • 会议室预订系统:用户管理模块-- 管理端信息修改页面
    • 会议室预订系统:会议室管理模块-后端开发
    • 会议室预订系统:会议室管理模块-管理端前端开发
    • 会议室预订系统:会议室管理模块-用户端前端开发
    • 会议室预订系统:预定管理模块-后端开发
    • 会议室预订系统:预定管理模块-管理端前端开发
    • 会议室预订系统:预定管理模块-用户端前端开发
    • 会议室预订系统:统计管理模块-后端开发
    • 会议室预订系统:统计管理模块-前端开发
    • 会议室预订系统:后端项目部署到阿里云
    • 会议室预订系统:前端项目部署到阿里云
    • 会议室预定系统:用 migration 初始化表和数据
    • 会议室预定系统:文件上传 OSS
    • 会议室预定系统:Google 账号登录后端开发
    • 会议室预定系统:Google 账号登录前端开发
    • 会议室预定系统:后端代码优化
    • 会议室预定系统:集成日志框架 winston
    • 会议室预定系统:前端代码优化
    • 会议室预定系统:全部功能测试
    • 会议室预定系统:项目总结
    • Nest 如何创建微服务?
    • Nest 的 Monorepo 和 Library
    • 用 Etcd 实现微服务配置中心和注册中心
    • Nest 集成 Etcd 做注册中心、配置中心
    • 用 Nacos 实现微服务配置中心和注册中心
    • 基于 gRPC 实现跨语言的微服务通信
    • 快速入门 ORM 框架 Prisma
    • Prisma 的全部命令
    • Prisma 的全部 schema 语法
    • Primsa Client 单表 CRUD 的全部 api
    • Prisma Client 多表 CRUD 的全部 api
    • 在 Nest 里集成 Prisma
    • 为什么前端监控系统要用 RabbitMQ?
    • 基于 Redis 实现关注关系
    • 基于 Redis 实现各种排行榜(周榜、月榜、年榜)
    • 考试系统:需求分析
    • 考试系统:技术方案和数据库设计
    • 考试系统:微服务、Lib 拆分
    • 考试系统;用户注册
    • 考试系统:用户登录、修改密码
    • 考试系统:考试微服务
    • 考试系统:登录、注册页面
    • 考试系统:修改密码、试卷列表页面
    • 考试系统:新增试卷、回收站
    • 考试系统:试卷编辑器
    • 考试系统:试卷回显、预览、保存
    • 考试系统:答卷微服务
    • 考试系统:答题页面
    • 考试系统:自动判卷
    • 考试系统:分析微服务、排行榜页面
    • 考试系统:整体测试
    • 考试系统:项目总结
    • 用 Node.js 手写 WebSocket 协议
    • Nest 开发 WebSocket 服务
    • 基于 Socket.io 的 room 实现群聊
    • 聊天室:需求分析和原型图
    • 聊天室:技术选型和数据库设计
    • 聊天室:用户注册
    • 聊天室:用户登录
    • 聊天室:修改密码、修改信息
    • 聊天室:好友列表、发送好友申请
    • 聊天室:创建聊天室、加入群聊
    • 聊天室:登录、注册页面开发
    • 聊天室:修改密码、信息页面开发
    • 聊天室:头像上传
    • 聊天室:好友∕群聊列表页面
    • 聊天室:添加好友弹窗、通知页面
    • 聊天室:聊天功能后端开发
    • 聊天室:聊天功能前端开发
    • 聊天室:一对一聊天
    • 聊天室:创建群聊、进入群聊
    • 聊天室:发送表情、图片、文件
    • 聊天室:收藏
    • 聊天室:全部功能测试
    • 聊天室:项目总结
    • MongoDB 快速入门
    • 使用 mongoose 操作 MongoDB 数据库
    • GraphQL 快速入门
    • Nest 开发 GraphQL 服务:实现 CRUD
    • GraphQL + Primsa + React 实现 TodoList
    • 如何调试 Nest 源码?
  • 其他

  • 服务端
  • Nest
神说要有光
2025-03-10
目录

快速掌握 TypeORM

上节我们简单用了下 TypeORM,这节我们把它全部的概念过一遍。

# 新建一个 TypeORM 项目:

npx typeorm@latest init --name typeorm-all-feature --database mysql
1

然后改下用户名密码数据库,把连接 msyql 的驱动包改为 mysql2,并修改加密密码的方式:

import "reflect-metadata";
import { DataSource } from "typeorm";
import { User } from "./entity/User";

export const AppDataSource = new DataSource({
  type: "mysql",
  host: "localhost",
  port: 3306,
  username: "root",
  password: "guang",
  database: "practice",
  synchronize: true,
  logging: true,
  entities: [User],
  migrations: [],
  subscribers: [],
  poolSize: 10,
  connectorPackage: "mysql2",
  extra: {
    authPlugin: "sha256_password",
  },
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

然后安装 mysql2:

npm install --save mysql2
1

# 我们分别来过一遍这些配置:

type 是数据库的类型,因为 TypeORM 不只支持 MySQL 还支持 postgres、oracle、sqllite 等数据库。

host、port 是指定数据库服务器的主机和端口号。

user、password 是登录数据库的用户名和密码。

database 是要指定操作的 database,因为 mysql 是可以有多个 database 或者叫 schema 的。

synchronize 是根据同步建表,也就是当 database 里没有和 Entity 对应的表的时候,会自动生成建表 sql 语句并执行。

当然,如果有对应的表就不会创建了。

logging 是打印生成的 sql 语句。

entities 是指定有哪些和数据库的表对应的 Entity。

除了 class,还可以通过这种方式指定:

migrations 是修改表结构之类的 sql,暂时用不到,就不展开了。

subscribers 是一些 Entity 生命周期的订阅者,比如 insert、update、remove 前后,可以加入一些逻辑:

poolSize 是指定数据库连接池中连接的最大数量。

connectorPackage 是指定用什么驱动包。

extra 是额外发送给驱动包的一些选项。

这些配置都保存在 DataSource 里。

DataSource 会根据你传入的连接配置、驱动包,来创建数据库连接,并且如果指定了 synchronize 的话,会同步创建表。

# 而创建表的依据就是 Entity:

跑一下:

npm run start
1

比如这个 Entity 就会执行这样的 sql:

主键为 INT 自增、firstName 和 lastName 是 VARCHAR(255),age 是 INT。

这是默认的映射关系。

那如果我 number 不是想映射到 INT 而是 DOUBLE 呢?

或者如果 string 不是想映射到 VARCHAR(255),而是 TEXT (长文本)呢?

这样映射:

import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";

@Entity({
  name: "t_aaa",
})
export class Aaa {
  @PrimaryGeneratedColumn({
    comment: "这是 id",
  })
  id: number;

  @Column({
    name: "a_aa",
    type: "text",
    comment: "这是 aaa",
  })
  aaa: string;

  @Column({
    unique: true,
    nullable: false,
    length: 10,
    type: "varchar",
    default: "bbb",
  })
  bbb: string;

  @Column({
    type: "double",
  })
  ccc: number;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

我们新增了一个 Entity Aaa。

@Entity 指定它是一个 Entity,name 指定表名为 t_aaa。

@PrimaryGeneratedColumn 指定它是一个自增的主键,通过 comment 指定注释。

@Column 映射属性和字段的对应关系。

通过 name 指定字段名,type 指定映射的类型,length 指定长度,default 指定默认值。

nullable 设置 NOT NULL 约束,unique 设置 UNIQUE 唯一索引。

type 这里指定的都是数据库里的数据类型。

然后在 DataSource 的 entities 里引入下:

重新跑 npm run start。

生成建表 sql 是这样的:

格式化一下:

对比着 Entity 看下:

是不是就明白怎么映射了?

在 mysql workbench 里看下,确实生成了这个表:

# 表创建好了,接下来就是增删改查了。

在 index.ts 里创建个 user 对象,然后调用 AppDataSource.manager.save 来保存:

import { AppDataSource } from "./data-source";
import { User } from "./entity/User";

AppDataSource.initialize()
  .then(async () => {
    const user = new User();
    user.firstName = "aaa";
    user.lastName = "bbb";
    user.age = 25;

    await AppDataSource.manager.save(user);
  })
  .catch((error) => console.log(error));
1
2
3
4
5
6
7
8
9
10
11
12
13

删除 User 表重新跑 npm run start。

可以看到数据库插入了这条记录:

如果你指定了 id,那就变成修改了:

import { AppDataSource } from "./data-source";
import { User } from "./entity/User";

AppDataSource.initialize()
  .then(async () => {
    const user = new User();
    user.id = 1;
    user.firstName = "aaa111";
    user.lastName = "bbb";
    user.age = 25;

    await AppDataSource.manager.save(user);
  })
  .catch((error) => console.log(error));
1
2
3
4
5
6
7
8
9
10
11
12
13
14

重新跑下 npm run start。

可以看到,生成的 sql 语句变成了 select 和 update:

当你指定了 id 的时候,typeorm 会先查询这个 id 的记录,如果查到了,那就执行 update。

在 mysql workbench 里看下:

确实修改了。

# 那如果想批量插入和修改呢?

这样写:

import { AppDataSource } from "./data-source";
import { User } from "./entity/User";

AppDataSource.initialize()
  .then(async () => {
    await AppDataSource.manager.save(User, [
      { firstName: "ccc", lastName: "ccc", age: 21 },
      { firstName: "ddd", lastName: "ddd", age: 22 },
      { firstName: "eee", lastName: "eee", age: 23 },
    ]);
  })
  .catch((error) => console.log(error));
1
2
3
4
5
6
7
8
9
10
11
12

我们 npm run start 跑一下:

可以看到确实生成了 3 条 insert into 的 sql 语句。

数据库中也能看到:

批量修改也很容易想到,是这样写:

import { AppDataSource } from "./data-source";
import { User } from "./entity/User";

AppDataSource.initialize()
  .then(async () => {
    await AppDataSource.manager.save(User, [
      { id: 2, firstName: "ccc111", lastName: "ccc", age: 21 },
      { id: 3, firstName: "ddd222", lastName: "ddd", age: 22 },
      { id: 4, firstName: "eee333", lastName: "eee", age: 23 },
    ]);
  })
  .catch((error) => console.log(error));
1
2
3
4
5
6
7
8
9
10
11
12

执行 npm run start,会看到一条 select 语句, 3 条 update 语句:

在 workbench 里也可以看到数据被修改了:

这就是 typeorm 里新增和修改的方式,使用 save 方法。

其实 EntityManager 还有 update 和 insert 方法,分别是修改和插入的,但是它们不会先 select 查询一次。而 save 方法会先查询一次数据库来确定是插入还是修改。

# 删除和批量删除用 delete 方法:

import { AppDataSource } from "./data-source";
import { User } from "./entity/User";

AppDataSource.initialize()
  .then(async () => {
    await AppDataSource.manager.delete(User, 1);
    await AppDataSource.manager.delete(User, [2, 3]);
  })
  .catch((error) => console.log(error));
1
2
3
4
5
6
7
8
9

执行下:

数据库了对应记录就被删除了:

这里也可以用 remove 方法:

import { AppDataSource } from "./data-source";
import { User } from "./entity/User";

AppDataSource.initialize()
  .then(async () => {
    const user = new User();
    user.id = 1;

    await AppDataSource.manager.remove(User, user);
  })
  .catch((error) => console.log(error));
1
2
3
4
5
6
7
8
9
10
11

delete 和 remove 的区别是,delete 直接传 id、而 remove 则是传入 entity 对象。

而查询是使用 find 方法:

先插入几条数据:

await AppDataSource.manager.save(User, [
  { firstName: "ccc", lastName: "ccc", age: 21 },
  { firstName: "ddd", lastName: "ddd", age: 22 },
  { firstName: "eee", lastName: "eee", age: 23 },
]);
1
2
3
4
5

再查一下:

import { AppDataSource } from "./data-source";
import { User } from "./entity/User";

AppDataSource.initialize()
  .then(async () => {
    const users = await AppDataSource.manager.find(User);
    console.log(users);
  })
  .catch((error) => console.log(error));
1
2
3
4
5
6
7
8
9

控制台打印了查询出的数据:

也可以通过 findBy 方法根据条件查询:

import { In } from "typeorm";
import { AppDataSource } from "./data-source";
import { User } from "./entity/User";

AppDataSource.initialize()
  .then(async () => {
    const users = await AppDataSource.manager.findBy(User, {
      age: 23,
    });
    console.log(users);
  })
  .catch((error) => console.log(error));
1
2
3
4
5
6
7
8
9
10
11
12

# 此外,你还可以用 findAndCount 来拿到有多少条记录:

import { AppDataSource } from "./data-source";
import { User } from "./entity/User";

AppDataSource.initialize()
  .then(async () => {
    const [users, count] = await AppDataSource.manager.findAndCount(User);
    console.log(users, count);
  })
  .catch((error) => console.log(error));
1
2
3
4
5
6
7
8
9

会额外执行一个统计的 sql:

count 是可以指定条件的:

import { AppDataSource } from "./data-source";
import { User } from "./entity/User";

AppDataSource.initialize()
  .then(async () => {
    const [users, count] = await AppDataSource.manager.findAndCountBy(User, {
      age: 23,
    });
    console.log(users, count);
  })
  .catch((error) => console.log(error));
1
2
3
4
5
6
7
8
9
10
11

可以看到,生成的 sql 里多了一个 where 条件:

除了可以查询多条,还可以查询一条,使用 findOne:

import { AppDataSource } from "./data-source";
import { User } from "./entity/User";

AppDataSource.initialize()
  .then(async () => {
    const user = await AppDataSource.manager.findOne(User, {
      select: {
        firstName: true,
        age: true,
      },
      where: {
        id: 4,
      },
      order: {
        age: "ASC",
      },
    });
    console.log(user);
  })
  .catch((error) => console.log(error));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

指定查询的 where 条件是 id 为 4 ,指定 select 的列为 firstName 和 age,然后 order 指定根据 age 升序排列。

查询结果如下:

findOne 只是比 find 多加了个 LIMIT 1,其余的都一样。

import { In } from "typeorm";
import { AppDataSource } from "./data-source";
import { User } from "./entity/User";

AppDataSource.initialize()
  .then(async () => {
    const users = await AppDataSource.manager.find(User, {
      select: {
        firstName: true,
        age: true,
      },
      where: {
        id: In([4, 8]),
      },
      order: {
        age: "ASC",
      },
    });
    console.log(users);
  })
  .catch((error) => console.log(error));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

把它改为 find,id 改为 In([4, 8]) 之后,结果如下:

通过 findOneBy 也可以:

import { AppDataSource } from "./data-source";
import { User } from "./entity/User";

AppDataSource.initialize()
  .then(async () => {
    const user = await AppDataSource.manager.findOneBy(User, {
      age: 23,
    });
    console.log(user);
  })
  .catch((error) => console.log(error));
1
2
3
4
5
6
7
8
9
10
11

此外,findOne 还有两个特殊的方法:

import { AppDataSource } from "./data-source";
import { User } from "./entity/User";

AppDataSource.initialize()
  .then(async () => {
    try {
      const user = await AppDataSource.manager.findOneOrFail(User, {
        where: {
          id: 666,
        },
      });
      console.log(user);
    } catch (e) {
      console.log(e);
      console.log("没找到该用户");
    }
  })
  .catch((error) => console.log(error));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# findOneOrFail 或者 findOneByOrFail,如果没找到,会抛一个 EntityNotFoundError 的异常:

# 此外,你还可以用 query 方法直接执行 sql 语句:

import { AppDataSource } from "./data-source";

AppDataSource.initialize()
  .then(async () => {
    const users = await AppDataSource.manager.query(
      "select * from user where age in(?, ?)",
      [21, 22]
    );
    console.log(users);
  })
  .catch((error) => console.log(error));
1
2
3
4
5
6
7
8
9
10
11

# 但复杂 sql 语句不会直接写,而是会用 query builder:

const queryBuilder = await AppDataSource.manager.createQueryBuilder();

const user = await queryBuilder
  .select("user")
  .from(User, "user")
  .where("user.age = :age", { age: 21 })
  .getOne();

console.log(user);
1
2
3
4
5
6
7
8
9

生成的 sql 语句如下:

有同学说,用 query builder 和我用 find 指定 where 有什么区别么?

比如这种复杂的关联查询:

涉及到多个表,也就是多个 Entity 的关联查询,就得用 query builder 了。

简单点查询直接 find 指定 where 条件就行。

此外,多条有关联的数据的增删改都离不开事务,怎么开启事务呢?

用 transaction 方法包裹下就好了。

await AppDataSource.manager.transaction(async (manager) => {
  await manager.save(User, {
    id: 4,
    firstName: "eee",
    lastName: "eee",
    age: 20,
  });
});
1
2
3
4
5
6
7
8

还有,调用每个方法的时候都要先传入实体类,这也太麻烦了:

# 有没有什么简便方法呢?

有,可以先调用 getRepository 传入 Entity,拿到专门处理这个 Entity 的增删改查的类,再调用这些方法:

具体的方法和 EntityManager 是一样的。

案例代码在小册仓库 (opens new window)。

# 总结

# 我们过了一遍 TypeORM 的各种概念,画个图总结下:

DataSource 里管理着数据库连接配置,数据库驱动包,调用它的 intialize 方法会创建和 mysql 的连接。

连接创建的时候,如果指定了 synchronize,会根据 Entitiy 生成建表 sql。

Entity 里通过 @Entity 指定和数据库表的映射,通过 @PrimaryGeneratedColumn 和 @Column 指定和表的字段的映射。

对 Entity 做增删改查通过 EntityManager 的 save、delete、find、createQueryBuilder 等方法。

如果只是对单个 Entity 做 CRUD,那可以先 getRepository 拿到对具体 Entity 操作的工具类,再调用 save、delete、find 等方法。

# 具体的 EntityManager 和 Repository 的方法有这些:

  • save:新增或者修改 Entity,如果传入了 id 会先 select 再决定修改还新增
  • update:直接修改 Entity,不会先 select
  • insert:直接插入 Entity
  • delete:删除 Entity,通过 id
  • remove:删除 Entity,通过对象
  • find:查找多条记录,可以指定 where、order by 等条件
  • findBy:查找多条记录,第二个参数直接指定 where 条件,更简便一点
  • findAndCount:查找多条记录,并返回总数量
  • findByAndCount:根据条件查找多条记录,并返回总数量
  • findOne:查找单条记录,可以指定 where、order by 等条件
  • findOneBy:查找单条记录,第二个参数直接指定 where 条件,更简便一点
  • findOneOrFail:查找失败会抛 EntityNotFoundError 的异常
  • query:直接执行 sql 语句
  • createQueryBuilder:创建复杂 sql 语句,比如 join 多个 Entity 的查询
  • transaction:包裹一层事务的 sql
  • getRepository:拿到对单个 Entity 操作的类,方法同 EntityManager

这些概念和 api 在后面会经常用到,需要理解它们各自都是干啥的。

编辑 (opens new window)
上次更新: 2025/9/9 09:58:02
Node 操作 MySQL 的两种方式
TypeORM 一对一的映射和关联 CRUD

← Node 操作 MySQL 的两种方式 TypeORM 一对一的映射和关联 CRUD→

最近更新
01
H5调用微信jssdk
09-28
02
VueVirtualScroller
09-19
03
IoC 解决了什么痛点问题?
03-10
更多文章>
Copyright © 2019-2025 Study | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式