NestJS 将 DTO 映射到具有关系的实体

问题描述 投票:0回答:1

我是 NestJS 的新手,想知道当 DTO 的属性与实体属性不 1:1 匹配时,将 DTO 转换为实体的最佳实践是什么。

例如,我有以下实体定义:

@Entity()
export class Category {

    @PrimaryGeneratedColumn()
    id: number

    @Column()
    name: string
    
    @OneToMany(() => questionToCategory, questionToCategory => questionToCategory.category)
    public questionToCategories: QuestionToCategory[];
}
export class Question {
    @PrimaryGeneratedColumn()
    id: number

    @Column()
    title: string

    @Column()
    text: string

    @OneToMany(() => QuestionToCategory, questionToCategory => questionToCategory.question)
    public questionToCategories: QuestionToCategory[];
}
export class QuestionToCategory {
    @PrimaryGeneratedColumn()
    public questionToCategoryId: number

    @Column()
    public questionId: number

    @Column()
    public categoryId: number

    @Column()
    public order: number

    @ManyToOne(() => Question, (question) => question.questionToCategories)
    public question: Question

    @ManyToOne(() => Category, (category) => category.questionToCategories)
    public category: Category
}

通过这些实体定义,问题和类别之间存在多对多关系

要保存问题实体中的多对多关系,您可以执行以下操作:

questionToCategories: { categoryId: "some_id_value" }

这工作正常,但是我的 DTO 结构与此结构不完美匹配。

如果我的问题 dto 类似于以下内容:

export class CreateQuestionDto {
    @IsString()
    title?: string;

    @IsString()
    title?: string;

  @IsOptional()
  @IsArray()
  bundles: string[];
}

其中bundles是与类别对应的id数组。我无法直接将此 DTO 保存为实体,因为包字段与 QuestionToCategories 不匹配。在 NestJS 中,是否有任何最佳实践可以将 dto 转换为实体的等效表示

node.js typescript nestjs class-transformer
1个回答
0
投票

我假设您的 DTO 无法根据实体进行更改和匹配。 在这种情况下,您无法通过铸造直接保存,并且无法执行级联插入。您可以做的是:创建一个映射器服务,该服务最初将保存问题,获取其 ID,然后根据您的 QuestionToCategory 实体映射它,然后保存:

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { CreateQuestionDto } from './dto/create-question.dto';
import { Question } from './entities/question.entity';
import { Category } from './entities/category.entity';
import { QuestionToCategory } from './entities/question-to-category.entity';

@Injectable()
export class QuestionService {
  constructor(
    @InjectRepository(Question)
    private questionRepository: Repository<Question>,
    @InjectRepository(Category)
    private categoryRepository: Repository<Category>,
    @InjectRepository(QuestionToCategory)
    private questionToCategoryRepository: Repository<QuestionToCategory>,
  ) {}

  async create(createQuestionDto: CreateQuestionDto): Promise<Question> {
    const { title, text, bundles } = createQuestionDto;

    const question = new Question();
    question.title = title;
    question.text = text;

    const savedQuestion = await this.questionRepository.save(question);
    const questionToCategories: QuestionToCategory[] = [];

    for (const categoryId of bundles) {
      const category = await this.categoryRepository.findOne(categoryId);
      if (category) {
        const questionToCategory = new QuestionToCategory();
        questionToCategory.question = savedQuestion;
        questionToCategory.category = category;
        questionToCategories.push(questionToCategory);
      }
    }

    await this.questionToCategoryRepository.save(questionToCategories);
    return this.questionRepository.findOne(savedQuestion.id, { relations: ['questionToCategories'] });
  }
}

在服务类中,您可以注入实体的存储库并使用它们相应地获取和保存在表中

© www.soinside.com 2019 - 2024. All rights reserved.