-
Notifications
You must be signed in to change notification settings - Fork 3
typeORM 다대다 속성 데이터 트러블 슈팅
lotus 업데이트 시, 다대다 column인 tags도 함께 업데이트 되어야 하지만 아래와 같은 에러 발생
Cannot query across many-to-many for property tags
const result = await this.lotusRepository.update(
{ lotusId },
{ title: lotusUpdateRequestDto.title, isPublic: lotusUpdateRequestDto.isPublic, tags: lotusUpdateRequestDto.tags }
);
@Entity()
export class Lotus {
...
@ManyToMany(() => Tag, { cascade: ['remove'] })
@ManyToMany(() => Tag, { cascade: ['insert', 'update', 'remove'] })
@JoinTable({
name: 'lotus_tags', // 교차 테이블 이름 지정
joinColumn: {
name: 'lotus_id', // 이 컬럼은 Lotus 엔티티를 참조
referencedColumnName: 'lotusId'
},
inverseJoinColumn: {
name: 'tag_id', // 이 컬럼은 Tag 엔티티를 참조
referencedColumnName: 'tagId'
}
})
tags: Tag[];
}
해외에서도 해당 오류를 겪은 사례를 찾아볼 수 있었습니다.
아래 문서들을 참조하여 update
를 사용하는 것이 아닌, save
를 사용하면 해당 오류가 나타나지 않음을 확인했습니다.
그러나 save를 사용한 방식은 findOne과 필연적으로 함께 사용되어야 해서 원자성을 띄지 못한다는 문제점이 확인되었습니다.
임시적으로 해당 방식을 통해 오류를 없앴었습니다.
참고자료
- https://stackoverflow.com/questions/70064149/typeorm-cannot-query-across-one-to-many-for-property-error
- https://github.com/typeorm/typeorm/issues/8245
이후 배포 및 테스트 과정에서 history와 lotus 사이 cascading 적용이 되지 않는 문제를 통해 db 관련 오류를 잡는 과정을 거쳤습니다.
더하여 tag와 lotus 사이에도 사용하지 않는 tag는 자동으로 cascading 혹은 삭제되도록 적용하고자 했습니다. 그러나 이는 typeORM의 다대다 관계로 구현하기보단 중간의 relation 테이블을 추가하여 관계의 복잡도를 낮추는 것이 구현 속도와 퀄리티 면에서 더 좋을 것이라는 판단과 더불어 위의 임시적으로 넘어갔던 문제를 해결할 수 있는 방법이라고 생각했습니다.
아래와 같은 lotusTagEntity를 추가하였습니다.
@Entity()
export class LotusTag {
@PrimaryGeneratedColumn('increment', { type: 'bigint', name: 'lotus_tag_id' })
lotusTagId: string;
@ManyToOne(() => Lotus, (lotus) => lotus.tags, { onDelete: 'CASCADE' })
@JoinColumn({ name: 'lotus_id' })
lotus: Lotus;
@ManyToOne(() => Tag, (tag) => tag.lotuses, { onDelete: 'CASCADE' })
@JoinColumn({ name: 'tag_id' })
tag: Tag;
}
-
tag update 오류 발생 아래의 체크 포인트들을 디버깅을 통해 살펴보며 오류가 나는 부분을 탐색했습니다.
-
tag 생성이 되지 않는가?x
-
필요없는 tag relation 이 삭제되지 않는가?x
→ 필요한 부분까지 삭제됨을 확인
-
태그 탐색에 문제가 있는가?O
→ null값 반환
-
조건식의 문제?
- 기존
const relation = await this.lotusTagRepository.find({ where: { lotus, tag } }, relations: ['lotus', 'tag'] });
- 변경 후
const relation = await this.lotusTagRepository.find({ where: { lotus: { id: lotusId }, tag: { id: tagId } }, relations: ['lotus', 'tag'] });
-
update 오류가 해결됨을 확인했습니다.
-
-
불필요한 save를 없애고, update를 추가하여 이전의 임시적인 조치를 처리했습니다.