Skip to content

joinAndMap의 유용성 {typeorm}

typeorm.io # Joining and mapping functionaility 를 참고할 것. 엔티티의 특정 필드에 조인 셀렉션을 명시적으로 매핑하고 싶은 경우에 이 메서드를 사용하면 된다.

Q. 그냥 joinAndSelect 하니까 걱정없이 매핑 되던데?

대부분의 경우에는 되겠지. 하지만 셀렉션 없이 매핑이 안되는 프로퍼티가 분명히 존재한단 사실을 알고 있어야 한다. 공식문서의 예시는 user.profilePhoto를 예로 들고 있다. 이 프로퍼티는 아마 컬럼이 아니라 JS 런타임 내에서 쓰일 편의용 프로퍼티일 것이다.

export class User {
    /// ...
    profilePhoto: Photo
}
const user = await createQueryBuilder("user")
    .leftJoinAndMapOne(
        /*mapToProperty*/"user.profilePhoto",
        /*property*/"user.photos",
        /*alias*/"photo",
        /*condition*/"photo.isForProfile = TRUE",
    )
    .where("user.name = :name", { name: "Timber" })
    .getOne();

만약 위의 예시에서 leftJoinAndSelect만을 사용했다면 user.photos만 매핑이 자동으로 될 것이고, profilePhotoaddSelect('userProfilePhoto')를 추가하여 수동으로 매핑하는 코드를 작성해야 했을 것이다:

const user = await createQueryBuilder("user")
    .leftJoinAndSelect(
        /*property*/"user.photos",
        /*alias*/"photo",
    )
    .where("user.name = :name", { name: "Timber" })
    .getOne();

if (user && user.photos) {
    user.profilePhoto = 
        user.photos.find((photo) => photo.isForProfile === true));
}

내가 사용한 예시#

  /**
   * 연관 펀딩에 달린 모든 삭제되지 않은 댓글들을 반환한다.
   * @param fundUuid
   * @returns Comment[]
   */
  async findMany(fundUuid: string): Promise<GetCommentDto[]> {
    const fundingQb = this.fundingRepository
      .createQueryBuilder('funding')
      .leftJoinAndSelect(
        'funding.comments',
        'comment',
        'comment.isDel = :isDel',
        { isDel: false },
      )
      .leftJoinAndSelect('comment.author', 'author')
      .leftJoinAndMapOne(
        'author.image', // map to property 'image' of 'author'
        'image', // property name of 'author'
        'authorImage', // alias of 'image' table
        `
        (author.defaultImgId IS NOT NULL AND authorImage.imgId = author.defaultImgId)
        OR
        (author.defaultImgId IS NULL AND authorImage.subId = author.userId AND authorImage.imgType = :imgType)
        `,
        { imgType: ImageType.User },
      )
      .where('funding.fundUuid = :fundUuid', { fundUuid })
      .orderBy('comment.regAt', 'DESC');

    Logger.log(fundingQb.getSql());

    const funding = await fundingQb.getOne();
    if (!funding) {
      throw this.g2gException.FundingNotExists;
    }

    return funding?.comments.map(convertToGetCommentDto) ?? [];
  }