Spring Data JPA - 1대 다 맵핑

Spring Data JPA

백기선님의 강의인 Spring Data JPA 강의를 듣고 공부한 내용을 정리한 글

1대 다 맵핑

관계에는 항상 엔티티가 존재한다.

  • 둘 중 하나는 관계의 주인이다.
  • 다른 쪽은 종속된 쪽이다.
  • 해당 관계의 반대쪽 레퍼런스를 가지고 있는 쪽이 주인이 된다.
@Entity
data class Study (
    @Id @GeneratedValue
    var id:Long?,
    val name: String,

    @ManyToOne
    val owner:Account
)

ManyToOne이 헷갈릴 수 있는데, 이 애노테이션을 받는 객체가 단일 객체 (Not Collection)이므로 One이 뒤에 온다고 이해하면 된다.

@ManyToOne의 동작을 자세히 살펴보면, 하나의 Account는 여러개의 Study를 가질 수 있기 때문에, Study의 릴레이션에서 owner 컬럼은 외래키로 Account 테이블의 PK를 참조하게 된다.

그러면 주인은 누구인가??

일반적으로 생각하면 Account가 주인이라고 생각하겠지만 오히려 반대이다.

여기서 말하는 주인(owning)은 관계를 누가 정의했는가?가 중요하다.

여기서 관계를 정의한 것은 Study이다. Account에는 어떠한 정의도 없다.

즉, 이 관계의 주인은 관계를 정의한 Study가 되는 것이다.

그럼 반대의 경우는 어떨까?

@Entity
data class Account(
    @Id @GeneratedValue
    val id:Long?,
    // @Column이 생략되어 있음
    val username:String,
    val password:String,

    @Embedded
    // kotlin에선 AttributeOverrides 안써도 됨
    @AttributeOverride(name = "street", column = Column(name = "home_street"))
    val address:Address?,

    @OneToMany
    val studies:Set<Study>
)

이번엔 Account가 여러 개의 스터디를 갖는 경우이다. 아무래도 이쪽이 조금 더 자연스럽게 느껴지기도 한다.

역시나 이것이 OneToMany인지 ManyToOne인지 헷갈린다면 끝을 보면 된다.

여기서는 Set이라는 다수의 컬렉션을 보유하기 때문에 끝이 Many으로 끝나는 것을 알 수 있다. 꿀팁이다.

기본적으로 OneToMany는 JoinTable이 생성된다.

스크린샷 2020-04-27 오후 9 35 31

즉 총 3개의 테이블이 만들어진다.

account_studies에는 account의 id와 studies의 id가 생긴다.

account 테이블과 study 테이블에는 어떠한 관계를 나타내는 컬럼이 생성되지 않는다.

관계를 알 수 있는 것은 account_studies 테이블이 관리한다.

양방향

그럼 양방향 모두 관계가 있는 경우는 어떨까?

@Entity
data class Study (
    @Id @GeneratedValue
    var id:Long?,
    val name: String,

    @ManyToOne
    val owner:Account
)
@Entity
data class Account(
    @Id @GeneratedValue
    val id:Long?,
    // @Column이 생략되어 있음
    val username:String,
    val password:String,

    @Embedded
    // kotlin에선 AttributeOverrides 안써도 됨
    @AttributeOverride(name = "street", column = Column(name = "home_street"))
    val address:Address?,

    @OneToMany
    val studies:MutableSet<Study> = HashSet()
)

두 클래스가 모두 서로 관계를 맺고 있다.

이 경우 양방향 관계가 성립이 될…까?

스크린샷 2020-04-27 오후 9 39 15 스크린샷 2020-04-27 오후 9 39 18

인텔리제이를 사용하면 깨알같이 귀엽게 두 원이 이어져있는 아이콘이 나온다!

그래서 얼핏 오 이거 양방향 관계가 성립됐구나!라고 오해하기 쉽지만

이는 양방향 관계가 아니다!

이 경우는 단방향 관계가 2개 생긴 것에 불과하다는 것을 기억하자.

이걸 양방향으로 만들기 위해서는 mappedby를 명시해주어야한다.

@Entity
data class Account(
    @Id @GeneratedValue
    val id:Long?,
    // @Column이 생략되어 있음
    val username:String,
    val password:String,

    @Embedded
    // kotlin에선 AttributeOverrides 안써도 됨
    @AttributeOverride(name = "street", column = Column(name = "home_street"))
    val address:Address?,

    @OneToMany(mappedby="owner")
    val studies:MutableSet<Study> = HashSet()
)

mappedby를 명시하는 쪽은 양방향 관계에서 주인이 아닌 프로퍼티에 명시한다.

누구인가? 누가 주인 소리를 내었어!

양방향 관계에서 주인은 Foreignkey를 가지고 있는 쪽이다!

즉 코드로 보면 @ManyToOne 애노테이션을 가진 쪽이 주인이라고 보면 된다.

주인에게 관계를 설정해야 DB에 반영이 된다. (객체지향적으로 보면 당연한 부분)

Reference

인프런 백기선님의 스프링 Data JPA



© 2022. by minkuk

Powered by minkuk