- 创建项目
- 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 一对多和多对一关系设计与增删改查
实体如何设计一对多与多对一关系,如何关联查询
一对多关系,多对一关系
定义:一对多是一种一个 A 包含多个 B ,而多个 B 只属于一个 A 的关系 其实就是要设计两个表:一张是主表(一对多),一张是副表(多对一),查找主表时,关联查找副表 有外键的表称之为副表,不带外键的表称之为主表 如:一个用户拥有多个宠物,多个宠物只属于一个用户的(每个宠物只能有一个主人) 如:一个用户拥有多张照片,多张照片只属于一个用户的 如:一个角色拥有多个用户,多个用户只属于一个角色的(每个用户只能有一个角色)
一对多和多对一实体设计
一对多
使用 @OneToMany()
来建立一对多关系 第一个参数: () => PhotoEntity
, 和谁建立关系? 和 PhotoEntity
建立关系 第二个参数: (user) => user.photo
,和哪个字段联立关系? user
就是 PhotoEntity
的别名,可随便写,和 PhotoEntity
的 userinfo
字段建立关系 第三个参数: RelationOptions
关系选项
import { Column, Entity, PrimaryGeneratedColumn, OneToOne, } from 'typeorm'; import { AvatarEntity } from './avatar.entity'; @Entity({ name: 'users' }) export class UsersEntity { @PrimaryGeneratedColumn() id: number; @Column() username: string; @Column() password: string; @OneToMany(() => PhotoEntity, (avatar) => avatar.userinfo) photos: PhotoEntity; }
多对一
使用 @ManyToOne()
来建立多对一关系,参数如同上
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm'; import { UsersEntity } from './user.entity'; @Entity({ name: 'photo' }) export class PhotoEntity { @PrimaryGeneratedColumn() id: number; @Column({ type: 'varchar' }) url: string; @ManyToOne(() => UsersEntity, (user) => user.photos) @JoinColumn({ name: 'userinfo_id' }) userinfo: UsersEntity; }
一对多和多对一增删改查
只要涉及两种表操作的,就需要开启事务:同时失败或同时成功,避免数据不统一 注意:所有数据应该是由前端传递过来的,这里为了方便,直接硬编码了(写死) 比较复杂的是更新操作
user.controller.ts
import { Controller, Get, Post, Body, Patch, Query, Param, Delete, HttpCode, HttpStatus, ParseIntPipe, } from '@nestjs/common'; import { Transaction, TransactionManager, EntityManager } from 'typeorm'; 开启事务第一步:引入 import { UserService } from './user.service-oto'; @Controller('user') export class UserController { constructor(private readonly userService: UserService) { } @Get() async findAll() { const [data, count] = await this.userService.findAll(); return { count, data }; } @Get(':id') async findOne(@Param('id', new ParseIntPipe()) id: number) { return await this.userService.findOne(id); } @Post(':id') @HttpCode(HttpStatus.OK) @Transaction() 开启事务第二步:装饰接口 async create( @Param('id', new ParseIntPipe()) id: number, @TransactionManager() maneger: EntityManager, 开启事务第三步:获取事务管理器 ) { return await this.userService.create(id, maneger); 开启事务第四步:传递给 service,使用数据库时调用 } @Patch(':id') @Transaction() async update( @Param('id', new ParseIntPipe()) id: number, @TransactionManager() maneger: EntityManager, ) { return await this.userService.update(id, maneger); } @Delete(':id') @Transaction() async remove( @Param('id', new ParseIntPipe()) id: number, @TransactionManager() maneger: EntityManager, ) { return await this.userService.remove(id, maneger); } }
user.service.ts
令人头大的地方:建立关系和查找使用实体,删除使用实体的 id,感觉设计得不是很合理,违背人的常识
import { Injectable } from '@nestjs/common'; import { Repository, EntityManager } from 'typeorm'; import { InjectRepository } from '@nestjs/typeorm'; import { UsersEntity } from './entities/user.entity'; import { PhotoEntity } from './entities/photo.entity'; import { ToolsService } from '../../utils/tools.service'; @Injectable() export class UserService { constructor( @InjectRepository(UsersEntity) private readonly usersRepository: Repository<UsersEntity>, @InjectRepository(PhotoEntity) private readonly photoRepository: Repository<PhotoEntity>, ) { } 一对多增删改查 async findAll() { // return await this.usersRepository.findAndCount({ relations: ['photos'] }); const list = await this.usersRepository .createQueryBuilder('UsersEntity') .leftJoinAndSelect('UsersEntity.photos', 'PhotoEntity.userinfo') .getManyAndCount(); return list; } 根据主表 id 查找一对多 async findOne(id: number) { 查询一个用户有多少张照片(一对多) const result = await this.usersRepository.findOne(id, { relations: ['photos'], }); if (!result) ToolsService.fail('用户 id 不存在'); return result; 查询这张照片属于谁(多对一) // const result = await this.photoRepository.findOne(id, { // relations: ['userinfo'], // }); // if (!result) ToolsService.fail('图片 id 不存在'); // return result; } 根据主表 id 创建一对多 async create(id: number, manager: EntityManager) { const urlList = [ { url: `http://www.dmyxs.com/images/${id}.png`, }, { url: `http://www.dmyxs.com/images/${id}.jpg`, }, ]; const user = await this.usersRepository.findOne({ id }); if (!user) ToolsService.fail('用户 id 不存在'); 遍历传递过来的数据 if (urlList.length !== 0) { for (let i = 0; i < urlList.length; i++) { 创建实体的两种方式:new 和 create,new 的方式方便条件判断 // const photo = new PhotoEntity(); // photo.url = urlList[i].url; // photo.user = user; // await manager.save(PhotoEntity, photo); const photoEntity = this.photoRepository.create({ url: urlList[i].url, userinfo: user, 注意:这里是使用实体建立关系,而不是实体 id }); await manager.save(photoEntity); } } return '新增成功'; } 根据主表 id 更改一对多 示例:删除一张,修改一张(修改的有 id),新增一张 先使用创建,创建两张 photo async update(id: number, manager: EntityManager) { const urlList = [ { id: 22, url: `http://www.dmyxs.com/images/${id}-update.png`, }, { url: `http://www.dmyxs.com/images/${id}-create.jpeg`, }, ]; const user = await this.usersRepository.findOne({ id }); if (!user) ToolsService.fail('用户 id 不存在'); 如果要修改主表,先修改主表用户信息,后修改副表图片信息 修改主表 const userEntity = this.usersRepository.create({ id, username: 'admin7', password: '123456', }); await manager.save(userEntity); 修改副表 如果前端附带了图片 list if (urlList.length !== 0) { 查询数据库已经有的图片 const databasePhotos = await manager.find(PhotoEntity, { userinfo: user }); 如果有数据,则进行循环判断,先删除多余的数据 if (databasePhotos.length >= 1) { for (let i = 0; i < databasePhotos.length; i++) { 以用户传递的图片为基准,数据库的图片 id 是否在用户传递过来的表里,如果不在,就是要删除的数据 const exist = urlList.find((item) => item.id === databasePhotos[i].id); if (!exist) { await manager.delete(PhotoEntity, { id: databasePhotos[i].id }); } } } 否则就是新增和更改的数据 for (let i = 0; i < urlList.length; i++) { const photoEntity = new PhotoEntity(); photoEntity.url = urlList[i].url; 如果有 id 则是修改操作,因为前端传递的数据是从服务端获取的,会附带 id,新增的没有 if (!!urlList[i].id) { 修改则让 id 关联即可 photoEntity.id = urlList[i].id; await manager.save(PhotoEntity, photoEntity); } else { 否则是新增操作,关联用户实体 photoEntity.userinfo = user; await manager.save(PhotoEntity, photoEntity); } } } else { 如果前端把图片全部删除,删除所有关联的图片 await manager.delete(PhotoEntity, { userinfo: id }); } return '更新成功'; } 根据主表 id 删除一对多 async remove(id: number, manager: EntityManager): Promise<any> { const user = await this.usersRepository.findOne(id); if (!user) ToolsService.fail('用户 id 不存在'); 只删副表的关联数据 await manager.delete(PhotoEntity, { userinfo: id }); 如果连主表用户一起删,加下面这行代码 //await manager.delete(UsersEntity, id); return '删除成功'; } }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论