如何在TypeORM单事务中创建编辑?NestJS测验开发咨询
NestJS单事务实现测验创建:先创建空测验再更新的方案
当然可以这么做,这是完全可行的实现思路——因为问题需要关联自动生成的quiz_id,先创建空问题数组的测验获取ID,再在同一事务内完成问题创建和测验更新,能保证整个流程的原子性,要么全部成功,要么全部回滚。
下面结合TypeORM(NestJS最常用的ORM工具)给出具体实现步骤和代码示例:
核心实现思路
利用TypeORM的QueryRunner手动控制事务流程,确保创建测验、创建问题、更新测验这三个步骤都在同一个事务上下文里执行:
- 初始化QueryRunner并启动事务
- 创建并保存空问题数组的测验,获取自动生成的
quiz_id - 批量创建问题,每个问题关联该
quiz_id - 更新测验的
questions数组并保存 - 提交事务;若任一环节出错则回滚
代码示例
测验服务(QuizService)中的创建方法
import { Injectable } from '@nestjs/common'; import { InjectConnection } from '@nestjs/typeorm'; import { Connection, QueryRunner } from 'typeorm'; import { Quiz } from './entities/quiz.entity'; import { CreateQuizDto } from './dto/create-quiz.dto'; import { QuestionService } from '../question/question.service'; import { CreateQuestionDto } from '../question/dto/create-question.dto'; @Injectable() export class QuizService { constructor( @InjectConnection() private readonly connection: Connection, private readonly questionService: QuestionService, ) {} async createQuizWithQuestions(quizDto: CreateQuizDto, questionsDto: CreateQuestionDto[]) { const queryRunner = this.connection.createQueryRunner(); await queryRunner.connect(); await queryRunner.startTransaction(); try { // 1. 创建空问题数组的测验 const quiz = new Quiz(); quiz.title = quizDto.title; quiz.questions = []; const savedQuiz = await queryRunner.manager.save(quiz); const quizId = savedQuiz.quiz_id; // 2. 批量创建关联的问题 const questions = await Promise.all( questionsDto.map((qDto) => this.questionService.createQuestion(qDto, quizId, queryRunner) ) ); // 3. 更新测验的questions数组 savedQuiz.questions = questions; await queryRunner.manager.save(savedQuiz); // 提交事务 await queryRunner.commitTransaction(); return savedQuiz; } catch (error) { // 出错则回滚所有操作 await queryRunner.rollbackTransaction(); throw error; } finally { // 释放QueryRunner资源 await queryRunner.release(); } } }
问题服务(QuestionService)中的创建方法
需要支持传入QueryRunner,确保问题创建操作在同一个事务内执行:
import { Injectable } from '@nestjs/common'; import { QueryRunner } from 'typeorm'; import { Question } from './entities/question.entity'; import { CreateQuestionDto } from './dto/create-question.dto'; @Injectable() export class QuestionService { async createQuestion( dto: CreateQuestionDto, quizId: string, queryRunner: QueryRunner, ) { const question = new Question(); question.content = dto.content; // 关联测验ID question.quiz_id = quizId; // 使用传入的QueryRunner执行保存操作,确保在事务内 return queryRunner.manager.save(question); } }
注意事项
- 所有数据库操作必须通过同一个
QueryRunner实例执行,不能使用默认的EntityManager,否则会脱离事务上下文 - 如果你的实体配置了双向关联(比如Quiz的
@OneToMany和Question的@ManyToOne),其实可以不用手动更新测验的questions数组——只要问题关联了对应的测验实例,TypeORM会自动维护关联关系;但如果是直接用quiz_id关联,手动更新数组的方式也是可行的 - 事务中所有异步操作要确保正确等待完成(比如用
Promise.all处理批量问题创建),避免出现事务提前提交的情况
内容的提问来源于stack exchange,提问作者Adrian Cielniak
相关产品推荐
相关产品推荐

