Jpa 연관관계

Woozy9ucci·2023년 12월 17일
0

Java와 DB는 패러다임이 다르다.
때문에 우리는 RDB의 테이블을 객체 형태로 다루기 위해 JPA(java 진영 표준 ORM)를 통해 테이블과 Entity를 매핑하여 사용한다.
즉, DB의 데이터를 객체지향적으로 다룰 수 있게 되는 것이다.

테이블 간의 연관관계를 객체에서는 어떻게 해석 할 지 알아보자

POST 테이블과 COMMENT 테이블이 1:N 으로 연관관계를 가지고 있다고 해보자
이 때 COMMENT 테이블이 POST_ID를 FK컬럼으로 가지고 join을 통해 서로를 참조할 수 있다

객체의 입장에서 바라보면 어떨까?
Comment가 필드로 PostId를 가지고 있으면 되지않을까?
해당 Comment의 Post를 조회 할 때 postId를 가지고 Post를 조회할 수 있다.
이는 데이터 지향적이지 객체지향적이라고 볼 수 없다
Comment가 필드로 Post를 가지고 참조하여 무언가를 할 수있도록 하기위해 우리는 맵핑을 해줘야한다.

@JoinColumn

  • 외래키와 객체를 맵핑
    Comment가 참조하고 있는 Post(객체)를 테이블 상에서 POST_ID(외래키)로 인식 할 수있도록 @JoinColumn 어노테이션을 사용하여 Comment.post와 COMMENT.POST_ID 를 맵핑 할 수 있다.

  • 일반적이지는 않지만 OneToMany에서 단방향 맵핑을 할 경우 @JoinColumn 어노테이션을 사용하지 않는다면 맵핑테이블이 하나 더 생성된다.(OneToMany 단방향 에서 JoinColumn을 생략하면 JoinTable이 우선)
    (그 반대는 JoinColumn 생략하면 아래에서 서술하는 referenced.. 기본설정으로 맵핑)
    또한 One쪽에서 @JoinColumn을 사용하더라도 외래키는 Many쪽에 생기게 된다.
    OneToMany 단방향설정을 하기 보다는 양방향 관계를 설정하자.
    (mappedBy를 통해 주인 설정 해주지 않으면 맵핑테이블이 추가생성된다)
    (주인은 외래키를 가지고 있는 쪽으로 정해주자)
    JPA - One To Many 단방향의 문제점 - https://dublin-java.tistory.com/51

  • OneToOne 에서 JoinColumn을 생략할 시 양방향일 때는 모두 fk를 갖게 되고 단방향일 때는 생략해도 무방하겠다. 양방향 일 때는 mappedBy를 통해 주인을 정해주자

  • 주요 속성

    • name
      FK컬럼의 컬럼명 지정(post_id)
    • referencedCoulumnName
      해당 외래키가 대상 테이블의 어떤 컬럼을 참조하는 지를 지정
      (post의 pk 컬럼명)
    • 생략 시 deafault
      name = 필드 명
      referenscedCoulumnName = 참조하는 테이블의 기본 키 컬럼
      ManyToOne 단방향에서는 생략해도 되긴 함
      (https://hyeon9mak.github.io/omit-join-column-when-using-many-to-one/)

@OneToMany, ManyToOne, ...

@JoinColumn 만으로는 맵핑을 완료할 수 없다.
@Entity 클래스 안에서 필드로 객체를 선언하면 컴파일 에러가 발생한다.
객체 간 어떤 연관관계를 가지고 있는지 모르기 때문이다.

  • 객체 간 연관관계를 지정
    DB는 외래키 하나로 양쪽 테이블 조인이 가능하기 때문에 방향을 구분 할 필요가 없다. 따라서 우리는 객체의 연관관계의 방향을 설정해야한다.
  • 연관관계의 주인 지정(mappedBy)
    양방향 설정 시 JPA에게 연관관계의 주인을 알려줘야한다.
    (실제로 mappedBy 지정 안했을 때 양쪽 모두의 fk를 갖는 테이블을 추가 생성)

연관관계, 방향설정 너무나 자세히 설명되어있는 블로그
https://jeong-pro.tistory.com/231
https://ttl-blog.tistory.com/129#%F0%9F%90%B3%20mappedBy%EB%A5%BC%20%EC%82%AC%EC%9A%A9%ED%95%98%EC%A7%80%20%EC%95%8A%EC%9C%BC%EB%A9%B4...-2

  • 양방향 설정시 순수객체 입장에서는 양쪽 모두 값을 세팅해주는것이 좋음
    ex) Comment의 init블록에 post.commentList.add(this) 등등
	val post = postRepository.findByIdOrNull(postId) ?: throw CustomException("post", ErrorCode.MODEL_NOT_FOUND)
    val user = userRepository.findByIdOrNull(userPrincipal.id) ?: throw CustomException("user", ErrorCode.MODEL_NOT_FOUND)
    println(post.commentList.size)
    var comment = Comment(
        content = commentRequest.content,
        author = user.userName,
        user = user,
        post = post
    )
    println(post.commentList.size)  // 이런식으로 사용할 수 있으니
    commentRepository.save(comment)

0개의 댓글

관련 채용 정보