ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Kotlin JPA 양방향 연관관계 매핑
    프로젝트/선착순 쿠폰 발급 시스템 2023. 5. 25. 00:01

    연관관계란?

    객체와 관계형 데이터베이스의 테이블의 불일치를 해결하기 위해 테이블 간의 연관관계를 매핑할 수 있습니다.

     

    데이터베이스와 객체와의 다른점

    데이터베이스는 외래키 하나만으로 양쪽 테이블 조인이 어디에서나 가능합니다.

    하지만 객체는 참조용 필드가 있는 객체만 다른 객체를 참조하는 것이 가능합니다.

     

    예를 들어 Account에 Member 프로퍼티가 존재하면 Account에서 Member를 조회할 수 있습니다.

    JPA를 사용하여 데이터베이스와 패러다임을 맞추기 위해서 객체는 단방향 연관 관계를 가질지, 양방향 연관 관계를 가질지 선택해야 합니다.

     

    양방향과 단방향

    양방향은 기본적으로 단방향 참조 2개로 구성됩니다.

    처음에는 외래키를 가진 쪽(연관관계의 주인)에 단방향으로 연관관계를 매핑하고 필요시에 양방향으로 연관관계를 매핑하는 것이 권장됩니다.

     

     

    연관관계를 지정하는 이유

     

    객체에서 양방향 연관 관계 관리 포인트가 두 개일 때는 테이블과 매핑을 담당하는 JPA입장에서 혼란을 주게 됩니다.

    즉, Member에서 Account를 수정할 때 어디에 수정이 일어날지 혼란이 발생합니다.

    이때 두 객체 사이의 연관 관계의 주인을 정해서 명확하게 "Member에서 Account를 수정할 때만 FK를 수정하겠다"라고 정하는 것입니다.

     

    Member와 Account의 연관관계 지정

    @Entity
    @Table(name = "account")
    class AccountJpaEntity(
    
      @Id
      val accountId: String,
    
      @Column(nullable = false, length = 50)
      var userId: String,
    
      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumn(name = "userId", referencedColumnName = "userId", insertable = false, updatable = false)
      val user: UserJpaEntity? = null,
    ){}

     

     

     

    @ManyToOne으로 연관관계를 매핑해 줍니다.

    이때 userId를 fk로 사용하기 위해 joinColumn으로 지정해 줍니다.

     

     

    @Entity
    @Table(name = "user")
    class UserJpaEntity(
    
      @Id
      @Column(nullable = false, length = 50)
      val userId: String,
      
      @OneToMany(mappedBy = "user", cascade = [CascadeType.ALL], fetch = FetchType.LAZY)
      val accounts: Set<AccountJpaEntity> = setOf(),
    ){}

    @OneToMany로 양방향 연관관계를 지정해 주었습니다.

    사유는 Account에서 User를 조회하는 것이 아니라 User를 조회할 때 Account를 조회하고 싶었기 때문입니다.

    또한 삭제, 저장등의 생애주기를 Account와 같이하기 때문에 CasecaseType.ALL을 활용하였습니다.

     

     

    저장은 어떻게?

    userJpaRepository.save(
      UserJpaEntity(
        userId = user.userId,
        accounts = setOf(
          AccountJpaEntity(
            accountId = account.accountId,
          ),
      )
    )

    userJpaEntity를 저장할 때 account도 같이 인자로 넘겨주게 되면 User와 Account 같이 저장이 수행됩니다.

    댓글

Designed by Tistory.