- 创建项目
- Nest 控制器
- nest 配置路由请求数据
- Nest 服务
- Nest 模块
- 配置静态资源
- 配置模板引擎
- Cookie 的使用
- Session 的使用
- 跨域,前缀路径、网站安全、请求限速
- 管道、守卫、拦截器、过滤器、中间件
- 一例看懂中间件、守卫、管道、异常过滤器、拦截器
- 数据验证
- 配置抽离
- 环境配置
- 文件上传与下载
- 实现图片随机验证码
- 邮件服务
- nest 基于 possport + jwt 做登陆验证
- 对数据库的密码加密:md5 和 bcryptjs
- 角色权限
- 定时任务
- 接入 Swagger 接口文档
- nest 连接 Mongodb
- typeORM 操作 Mysql 数据库
- nest 统一处理数据库操作的查询结果
- 数据库实体设计与操作
- typeorm 增删改查操作
- typeorm 使用事务的 3 种方式
- typeorm 一对一关系设计与增删改查
- typeorm 一对多和多对一关系设计与增删改查
- typeorm 多对多关系设计与增删改查
- nest 连接 Redis
- 集成 redis 实现单点登录
- Q:nestJS 注入其他依赖时为什么还需要导入其 module
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
typeorm 增删改查操作
访问数据库的方式有哪些? typeorm 增删改查操作的方式有哪些?
多种访问数据库的方式
第一种: Connection
import { Injectable } from '@nestjs/common'; import { Connection } from 'typeorm'; import { UsersEntity } from './entities/user.entity'; @Injectable() export class UserService { constructor( private readonly connection: Connection, ) { } async test() { // 使用封装好方法: return await this.connection .getRepository(UsersEntity) .findOne({ where: { id: 1 } }); // 使用 createQueryBuilder: return await this.connection .createQueryBuilder() .select('user') .from(UsersEntity, 'user') .where('user.id = :id', { id: 1 }) .getOne(); } }
第二种: Repository
,需要 @nestjs/typeorm
的 InjectRepository
来注入实体
import { Injectable } from '@nestjs/common'; import { Repository } from 'typeorm'; import { UsersEntity } from './entities/user.entity'; import { InjectRepository } from '@nestjs/typeorm'; @Injectable() export class UserService { constructor( @InjectRepository(UsersEntity) 注入实体 private readonly usersRepository: Repository<UsersEntity>, ) { } async test() { // 使用封装好方法: return await this.usersRepository.find({ where: { id: 1 } }); // 使用 createQueryBuilder: return await this.usersRepository .createQueryBuilder('user') .where('id = :id', { id: 1 }) .getOne(); } }
第三种: getConnection()
:语法糖,是 Connection
类型
import { Injectable } from '@nestjs/common'; import { getConnection } from 'typeorm'; import { UsersEntity } from './entities/user.entity'; @Injectable() export class UserService { async test() { // 使用封装好方法: return await getConnection() .getRepository(UsersEntity) .find({ where: { id: 1 } }); // 使用 createQueryBuilder: return await getConnection() .createQueryBuilder() .select('user') .from(UsersEntity, 'user') .where('user.id = :id', { id: 1 }) .getOne(); } }
第四种: getRepository
:语法糖
import { Injectable } from '@nestjs/common'; import { getRepository } from 'typeorm'; import { UsersEntity } from './entities/user.entity'; @Injectable() export class UserService { async test() { // 使用封装好方法: return await getRepository(UsersEntity).find({ where: { id: 1 } }); // 使用 createQueryBuilder: return await getRepository(UsersEntity) .createQueryBuilder('user') .where('user.id = :id', { id: 1 }) .getOne(); } }
第五种: getManager
import { Injectable } from '@nestjs/common'; import { getManager } from 'typeorm'; import { UsersEntity } from './entities/user.entity'; @Injectable() export class UserService { async test() { // 使用封装好方法: return await getManager().find(UsersEntity, { where: { id: 1 } }); // 使用 createQueryBuilder: return await getManager() .createQueryBuilder(UsersEntity, 'user') .where('user.id = :id', { id: 1 }) .getOne(); } }
简单总结
使用的方式太多,建议使用: 2,4
,比较方便
Connection 核心类:
connection
等于getConnection
connection.manager
等于getManager
, 等于getConnection.manager
connection.getRepository
等于getRepository
, 等于getManager.getRepository
connection.createQueryBuilder
使用QueryBuilder
connection.createQueryRunner
开启事务
EntityManager
和Repository
都封装了操作数据的方法,注意:两者的使用方式是不一样的,(实在不明白搞这么多方法做什么,学得头大)getManager
是EntityManager
的类型,getRepository
是Repository
的类型- 都可以使用
createQueryBuilder
,但使用的方式略有不同
增删改查的三种方式
- 第一种:使用 sql 语句,适用于 sql 语句熟练的同学
- 第二种:
typeorm
封装好的方法,增删改 + 简单查询 - 第三种:
QueryBuilder
查询生成器,适用于关系查询,多表查询,复杂查询 - 其实底层最终都会生成
sql
语句,只是封装了几种方式而已,方便人们使用。
第一种:sql 语句
export class UserService { constructor( @InjectRepository(UsersEntity) private readonly usersRepository: Repository<UsersEntity>, ) { } async findAll() { return await this.usersRepository.query('select * from users'); // 在 query 中填写 sql 语句 } }
第二种:typeorm 封装好的 api 方法
这里使用第二种访问数据库的方式
export class UserService { constructor( @InjectRepository(UsersEntity) private readonly usersRepository: Repository<UsersEntity>, ) { } async findAll() { return await this.usersRepository.findAndCount(); // 封装好的方法 } }
api 方法
增 save(user) 创建:返回该数据的所有字段 insert(user) 快速插入一条数据,插入成功:返回插入实体,与 save 方法不同的是,它不执行级联、关系和其他操作。 删 remove(user) 删除:返回该数据的可见字段 softRemove(user); 拉黑:返回该数据的可见字段,该删除实体必须拥有 @DeleteDateColumn() 字段,被拉黑的用户还存在数据库中,但无法被 find 查找到,会在 @DeleteDateColumn() 字段中添加删除时间,可使用 recover 恢复 改 update(id, user) 更新:返回更新实体,不是该数据的字段 恢复 recover({ id }) 恢复:返回 id,将被 softRemove 删除(拉黑)的用户恢复,恢复成功后可以被 find 查找到 查找全部 find() find({id:9}) 条件查找,写法一,找不到返回空对象 find({where:{id:10}}) 条件查找,写法二,找不到返回空对象 findAndCount() 返回数据和总的条数 查找一个 findOne(id); 根据 ID 查找,找不到返回 undefined findOne({ where: { username } }); 条件查找,找不到返回 undefined 根据 ID 查找一个或多个 findByIds([1,2,3]); 查找 n 个,全部查找不到返回空数组,找到就返回找到的 其他 hasId(new UsersEntity()) 检测实体是否有合成 ID,返回布尔值 getId(new UsersEntity()) 获取实体的合成 ID,获取不到返回 undefined create({username: 'admin12345', password: '123456',}) 创建一个实体,需要调用 save 保存 count({ status: 1 }) 计数,返回数量,无返回 0 increment({ id }, 'age', 2); 增加,给条件为 id 的数据的 age 字段增加 2,成功返回改变实体 decrement({ id }, 'age', 2) 减少,给条件为 id 的数据的 age 字段增加 2,成功返回改变实体 谨用 findOneOrFail(id) 找不到直接报 500 错误,无法使用过滤器拦截错误,不要使用 clear() 清空该数据表,谨用!!!
find 更多参数
this.userRepository.find({ select: ["firstName", "lastName"], 要的字段 relations: ["photos", "videos"], 关系查询 where: { 条件查询 firstName: "Timber", lastName: "Saw" }, where: [{ username: "li" }, { username: "joy" }], 多个条件 or, 等于:where username = 'li' or username = 'joy' order: { 排序 name: "ASC", id: "DESC" }, skip: 5, 偏移量 take: 10, 每页条数 cache: 60000 启用缓存:1 分钟 });
find 进阶选项
TypeORM 提供了许多内置运算符,可用于创建更复杂的查询
import { Not, Between, In } from "typeorm"; return await this.usersRepository.find({ username: Not('admin'), }); 将执行以下查询: SELECT * FROM "users" WHERE "username" != 'admin' return await this.usersRepository.find({ likes: Between(1, 10) }); SELECT * FROM "users" WHERE "likes" BETWEEN 1 AND 10 return await this.usersRepository.find({ username: In(['admin', 'admin2']), }); SELECT * FROM "users" WHERE "title" IN ('admin', 'admin2')
第三种: QueryBuilder
查询生成器
使用链式操作
QueryBuilder 增,删,改
// 增加 return await this.usersRepository .createQueryBuilder() .insert() 声明插入操作 .into(UsersEntity) 插入的实体 .values([ 插入的值,可插入多个 { username: 'Timber', password: '123456' }, { username: 'Timber2', password: '123456' }, ]) .execute(); 执行 // 修改 return this.usersRepository .createQueryBuilder() .update(UsersEntity) .set({ username: 'admin22' }) .where('id = :id', { id: 2 }) .execute(); // 删除 return this.usersRepository .createQueryBuilder() .delete() .from(UsersEntity) .where('id = :id', { id: 8 }) .execute(); // 处理异常:请求成功会返回一个对象, 如果 raw.affectedRows != 0 就是成功 "raw": { "fieldCount": 0, "affectedRows": 2, "insertId": 13, "serverStatus": 2, "warningCount": 0, "message": "&Records: 2 Duplicates: 0 Warnings: 0", "protocol41": true, "changedRows": 0 }
查询
简单例子
export class UserService { constructor( @InjectRepository(UsersEntity) private readonly usersRepository: Repository<UsersEntity>, ) { } async findAll() { return await this.usersRepository .createQueryBuilder('user') 创建生成器,参数:别名 .where('user.id = :id', { id: id }) 条件 .innerJoinAndSelect('user.avatar', 'avatar') 关系查询 .addSelect('user.password') 添加显示字段 .getOne(); 获取一条数据 } }
QueryBuilder 查询生成器说明
查询单表
访问数据库的方式不同: 方式一:没有指定实体,需要使用 from 指定实体 return await getConnection() .createQueryBuilder() .select('user.username') ‘user’:全部字段,‘user.username’:只获取 username .from(UsersEntity, 'user') 参 1:连接的实体, 参 2:别名 .where('user.id = :id', { id: 1 }) .getOne(); 方式二:指定实体:默认获取全部字段 return await getConnection() .createQueryBuilder(UsersEntity, 'user') 指定实体 .where('user.id = :id', { id: 1 }) .getOne(); 方式三: 已经在访问时指定了实体:默认获取全部字段 return await this.usersRepository .createQueryBuilder('user') 别名 .where('user.id = :id', { id: 1 }) .getOne();
获取结果
.getSql(); 获取实际执行的 sql 语句,用于开发时检查问题 .getOne(); 获取一条数据(经过 typeorm 的字段处理) .getMany(); 获取多条数据 .getRawOne(); 获取一条原数据(没有经过 typeorm 的字段处理) .getRawMany(); 获取多条原数据 .stream(); 返回流数据 如:经过 typeorm 的字段处理,获取到的就是实体设计时的字段 { "status": 200, "message": "请求成功", "data": { "id": 1, "username": "admin", "gender": "male", "age": 18, "status": 1, "createdAt": "2021-04-26T09:58:54.469Z", "updatedAt": "2021-04-28T14:47:36.000Z", "deletedAt": null } } 如:没有经过 typeorm 的字段处理,将数据库的字段原生不动的显示出来 { "status": 200, "message": "请求成功", "data": { "user_id": 1, "user_username": "admin", "user_gender": "male", "user_age": 18, "user_status": 1, "user_created_at": "2021-04-26T09:58:54.469Z", "user_updated_at": "2021-04-28T14:47:36.000Z", "user_deleted_at": null } }
查询部分字段
.select(["user.id", "user.name"]) 实际执行的 sql 语句:SELECT user.id, user.name FROM users user; 添加隐藏字段:实体中设置 select 为 false 时,是不显示字段,使用 addSelect 会将字段显示出来 .addSelect('user.password')
where
条件
.where("user.name = :name", { name: "joy" }) 等于 .where("user.name = :name") .setParameter("name", "Timber") 实际执行的 sql 语句:SELECT * FROM users user WHERE user.name = 'joy' 多个条件 .where("user.firstName = :firstName", { firstName: "Timber" }) .andWhere("user.lastName = :lastName", { lastName: "Saw" }); 实际执行的 sql 语句:SELECT * FROM users user WHERE user.firstName = 'Timber' AND user.lastName = 'Saw' in .where("user.name IN (:...names)", { names: [ "Timber", "Cristal", "Lina" ] }) 实际执行的 sql 语句:SELECT * FROM users user WHERE user.name IN ('Timber', 'Cristal', 'Lina') or .where("user.firstName = :firstName", { firstName: "Timber" }) .orWhere("user.lastName = :lastName", { lastName: "Saw" }); 实际执行的 sql 语句:SELECT * FROM users user WHERE user.firstName = 'Timber' OR user.lastName = 'Saw' 子句 const posts = await connection .getRepository(Post) .createQueryBuilder("post") .where(qb => { const subQuery = qb .subQuery() .select("user.name") .from(User, "user") .where("user.registered = :registered") .getQuery(); return "post.title IN " + subQuery; }) .setParameter("registered", true) .getMany(); 实际执行的 sql 语句:select * from post where post.title in (select name from user where registered = true)
having
筛选
.having("user.firstName = :firstName", { firstName: "Timber" }) .andHaving("user.lastName = :lastName", { lastName: "Saw" }); 实际执行的 sql 语句:SELECT ... FROM users user HAVING user.firstName = 'Timber' AND user.lastName = 'Saw'
orderBy
排序
.orderBy("user.name", "DESC") .addOrderBy("user.id", "asc"); 等于 .orderBy({ "user.name": "ASC", "user.id": "DESC" }); 实际执行的 sql 语句:SELECT * FROM users user order by user.name asc, user.id desc;
group
分组
.groupBy("user.name") .addGroupBy("user.id");
关系查询(多表)
1 参:你要加载的关系,2 参:可选,你为此表分配的别名,3 参:可选,查询条件 左关联查询 .leftJoinAndSelect("user.profile", "profile") 右关联查询 .rightJoinAndSelect("user.profile", "profile") 内联查询 .innerJoinAndSelect("user.photos", "photo", "photo.isRemoved = :isRemoved", { isRemoved: false }) 例子: const result = await this.usersRepository .createQueryBuilder('user') .leftJoinAndSelect("user.photos", "photo") .where("user.name = :name", { name: "joy" }) .andWhere("photo.isRemoved = :isRemoved", { isRemoved: false }) .getOne(); 实际执行的 sql 语句: SELECT user.*, photo.* FROM users user LEFT JOIN photos photo ON photo.user = user.id WHERE user.name = 'joy' AND photo.isRemoved = FALSE; const result = await this.usersRepository .innerJoinAndSelect("user.photos", "photo", "photo.isRemoved = :isRemoved", { isRemoved: false }) .where("user.name = :name", { name: "Timber" }) .getOne(); 实际执行的 sql 语句: SELECT user.*, photo.* FROM users user INNER JOIN photos photo ON photo.user = user.id AND photo.isRemoved = FALSE WHERE user.name = 'Timber'; 多个关联 const result = await this.usersRepository .createQueryBuilder("user") .leftJoinAndSelect("user.profile", "profile") .leftJoinAndSelect("user.photos", "photo") .leftJoinAndSelect("user.videos", "video") .getOne();
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论