• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

OneToMany 관계에서 FK 데이터를 Repository를 이용하여 insert시 오류

23.02.15 03:37 작성 조회수 481

0

Screenshot 2023-02-14 at 12.25.09 PM.png 우선 제 프로젝트에서 구성하고 있는 DB의 일부분입니다. 간단하게 p_references 와 m_references, 그리고 parts 와 models 테이블에 그림파일의 정보를 가지고 있는 images객체의 배열이 필요한데 mysql이다보니 이걸 다 One to Many로 추가시켰습니다. 여기에 images의 각각 대상 테이블에 대한 FK를 nullable : true 상태로 추가시켰습니다. 물론 이렇게 구성하면 images 테이블안에 적어도 한개의 FK를 포함한 입력값만 허용하도록 Guards 를 추가시켜야 될꺼 같습니만... 간단히 이해도를 위해 설명을 추가한거고요.

여기서 문제는 p_references/m_reference 와 images table과 연결 시킬때 원래 계획된 대로 images 테이블 안에 string 이나 int 형식의 column이 추가되는것이 아닌 대상 테이블 객체가 잡히는 문제인데요.

entities/images.ts

@Entity("Images", { schema: "workplaces" })
export class Images {

    @PrimaryGeneratedColumn({ type: "int", name: "imageID" })
    id: number;

    @Column('varchar', { name: 'images', nullable: true })
    image: string;

    @Column('bool', { name: 'isOwn', nullable: false, default: false })
    isOwn: boolean;

    @ManyToOne(() => Mreferences, (mreferences) => mreferences.images, { onDelete: "SET NULL", onUpdate: "CASCADE" })
    @JoinColumn([{ name: 'modelNumber', referencedColumnName: 'serialNumber' }])
    mreferences: Mreferences;

    @ManyToOne(() => Preferences, (preferences) => preferences.images, { onDelete: "SET NULL", onUpdate: "CASCADE" })
    @JoinColumn([{ name: 'partsNumber', referencedColumnName: 'serialNumber' }])
    preferences: Preferences;

    @ManyToOne(() => Parts, (parts) => parts.images, { onDelete: "SET NULL", onUpdate: "CASCADE" })
    @JoinColumn([{ name: 'partsID', referencedColumnName: 'id' }])
    parts: Parts;

    @ManyToOne(() => Models, (models) => models.images, { onDelete: "SET NULL", onUpdate: "CASCADE" })
    @JoinColumn([{ name: 'modelID', referencedColumnName: 'id' }])
    models: Models;
}

이것이 images entity에서 설정한 코드입니다. 이렇게 해서 자동으로 생성된 DB 의 ERD가 처음에 올린 스샷으로 제대로 의도된대로 생성된걸 확인할 수 있습니다.

기본 설명이 너무 길어졌는데, 이제 여기 강의의 "typeorm 쿼리 빌더" 강의에 나온대로 새로운 데이터를 insert 요청이 발생하면 Images Repository를 이용해서 저장을 하려하는데 문제가 발생드려서 문의드립니다.

reference-book.service.ts

import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Mreferences } from '../entities/Mreferences';
import { Repository } from 'typeorm';
import { ReferencebookModelDto } from './dto/referencebook.model.dto';
import { Videos } from '../entities/Videos';

@Injectable()
export class ReferenceBookService {

    constructor(
        @InjectRepository(Mreferences)
        private referenceModelRepository: Repository<Mreferences>,
        @InjectRepository(Images)
        private imagesRepository: Repository<Images>,
    ) { }

    async addReferenceModel(addReferenceModel: ReferencebookModelDto) {
        const referenceModelBook = new Mreferences();
        const referenceModelImages = new Images();

        referenceModelBook.serialNumber = addReferenceModel.serialNumber;
        referenceModelBook.name = addReferenceModel.modelName;
        referenceModelBook.brands = addReferenceModel.brand;
        //..... 생략

        await this.referenceModelRepository.save(referenceModelBook);
    }
}

이렇게 작성시, 아무런 문제 없이 FK관련 column 값들을 제외하곤 이상없이 제대로 DB에 저장이 되는데요. 문젠 FK 관련한 값에서 제대로 작동하지 않습니다.

Screenshot 2023-02-14 at 2.18.38 PM.pngconst data = new Images() 로 새로 Images객체를 생성하여, ERD에서 처럼 거기에 등록된 modelNumber 값을 입력한 dto객체의 images.image 값으로 지정해주고 저장하면 될 줄 알았는데 실제 생성된 Images객체엔 modelNumber 문자열이 존재하는 대산 mreferences 객체만이 존재합니다.

강의에서 직접 다룬 프로젝트는 아니지만 제가 강의를 보면서 직접 따라하다 발생한 문제라 강의관련 문의에 올렸습니다.

어딘가에서 오류가 있던걸까요?

추가로 혹시나 필요할까 해서 dto 파일도 올립니다

/dto/referencebook.model.dto.ts

import { ApiProperty } from "@nestjs/swagger";
import { Images } from "../../entities/Images";
import { Brands, Categories } from "../../common/types/enum.types";
import { Videos } from "../../entities/Videos";

export class ReferencebookModelDto {

    @ApiProperty({ example: 'WX532433', description: 'Uniq Serial Number', required: true, })
    public serialNumber: string;

    @ApiProperty({ example: 'Aug-23-2023', description: 'Updated Date', required: true, })
    public updateDate: Date;

    @ApiProperty({ example: 'Samsung Dryer', description: 'Model Name', required: true, })
    public modelName: string;

    @ApiProperty({ example: ['afd34323', 'ty23142'], description: 'Serial number List of related parts ', required: false, })
    public relatedParts: string[];
    
    @ApiProperty({ example: ['https:/atlanticappliance.com/parts/p?pid=WX532433/image1.jpg'], description: 'Links of own images location', required: false, })
    public images: Images[];

    @ApiProperty({ example: ['https:/atlanticappliance.com/parts/p?pid=WX532433/video1.mp4'], description: 'Links of own videos location', required: false, })
    public videos: Videos[];

    @ApiProperty({ example: 'This is a parts for testing model, WX532433', description: 'Scraped description of current product from other sites', required: false, })
    public description: string;

    @ApiProperty({ example: 'Washer', description: 'Product categories', required: true, })
    public category: Categories;

    @ApiProperty({ example: '24Inch', description: 'Product Variant Options', required: false, })
    public variant: string;

    @ApiProperty({ example: '27.7', description: 'Product Weight', required: false, })
    public weight: number;

    @ApiProperty({ example: 21.49, description: 'Product height', required: false, })
    public height: number;

    @ApiProperty({ example: 21.49, description: 'Product width', required: false, })
    public width: number;

    @ApiProperty({ example: 21.49, description: 'Product depth', required: false, })
    public depth: number;

    @ApiProperty({ example: 'Samsung', description: 'Brand', required: false, })
    public brand: Brands;
} 

답변 2

·

답변을 작성해보세요.

0

빠른 답변 감사합니다. 관계설정만이 아니라 join한 테이블쪽에 설정한 이름과 동일한 column을 추가하면 자동으로 인식을 해주는군요. 실제로 수정해보고 확인했습니다.

그럼 만약 ManyToMany의 경우 양쪽에서 다 수정이 가능하게 할려면, 양쪽에 설정해둔 column들을 각각 설정한 이름과 동일한 column을 추가해주면 되는 것인가요?

네 맞습니다. @Column으로 실제 테이블에 존재하는 컬럼 넣으시면 됩니다

0

이유는 매우 간단합니다. @Column modelNumber가 없어서 그렇습니다. 포린키 컬럼을 직접 쓰고 싶으시면 따로 추가하셔야 합니다.