JPA Entity 연관관계?

JPA Entity 연과관계를 알기전에 데이터베이스의 관계정의를 먼저 알고 가겠습니다.

1. RDB 관계 정의

먼저 관계를 정의를 하면

존재의 형태로서나 행위로서 서로에게 연관성이 부여된 상태

라고 할 수 있습니다.
이러한 관계는 엔터티와 엔터티 간 연관성을 표현하기 때문에 특정 엔터티의 정의에 따라 영향을 받기도 하고, 속성 정의 및 관계 정의에 따라서도 다양하게 변경될 수 있습니다.

DB를 깊게 들어가면 책 한권의 분량이라서 간단하게 관계차수만 알고 JPA Entity의 연관관계를 보도록 하겠습니다.

2. 관계 차수란?

관계차수란, 관계에 참여하는 두 엔터티의 참여자수를 이야기합니다. 일반적으로 1:1, 1:N, M:N으로 나타납니다. 바커 표기법과 IE 표기법으로 알아보도록 하겠습니다.

만약 학생 엔터티, 학생이 취득한 자격증 엔터티, 어학성적 엔터티가 있다면 어떻게 될까요?

  • 학생 엔터티

  • 자격증 엔터티

  • 어학성적 엔터티

이 셋 엔터티간의 관계를 생각해보시면 학생이 한개의 자격증만 따야될까요?!
학생이 어학성적을 한개만 취득할까요?!
물론 안딸수도 있고.. 한개이상일 경우도 있을 겁니다.. 그러면 어떻게 관계를 연결해야될까요?

저는 이렇게 관계를 지었습니다.
Barker표기법에서는 점선은 있을수도있고 없을수도 있다는 뜻입니다.

자 이런식으로 표기를 하시면

학부생은 어학성적을 한개이상 가질수도있고 없을수도 있다.
그리고 자격증또한 한개이상 가질수도있고 없을수도 있다.

라는 뜻을 나타냅니다.

그리고 외래키(FK)를 사용하여 어학성적 엔터티와 자격증 엔터티에서 학부생을 참조할 수 있도록 하였습니다.

일단 이정도로만 알고... DB에 대해서 깊게 공부하실려면... 저도 공부를 조금 해봐야될거 같습니다..

3학년때 공부를 했는데... 지금은 어디로 갔는지 모르겠습니다..

아 이건 3학년때의 과제중에 하나인 학사정보시스템인데 한번 보세요!

진짜 간략하게 관계에 대해서 배워보았으니 이제 JPA 엔터티의 연관관계를 알아보도록 하겠습니다.

3. 엔터티간의 연관관계

연과 관계를 매핑할 때 생각해야 할 것은 크게 3가지라고 합니다.

  • 방향: 단방향인지? 양방향인지?
  • 연관 관계의 주인: 양방향일때 , 연관 관계에서 관리 주체
  • 다중성 : ManyToOne, OneToMany, OneToOne, ManyToMany

단방향과 양방향은 뭘까요?

두 객체 사이에서 하나의 참조용 필드를 갖고 참조하면 단방향 관계이고 두 객체 모두가 참조용 필드를 갖고 참조하면 양방향 관계입니다.

예시를 들어서 보도록 할게요!

  • 학생엔터티
public class Student {
    @Id
    @Column(name = "StudentId")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long studentId;

    @Column
    private String name;
    
    @Column
    private String phoneNumber;

}
  • 자격증 엔터티
public class Certificate {
    @Id
    @Column(name = "Certificate_Id")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long certificateId;

    @Column
    private String certificateName;

    @ManyToOne(targetEntity = Student.class,fetch = FetchType.EAGER)
    @JoinColumn(name = "Student_Id")
    private Student student;

이 두엔터티를 보면 자격증 엔터티에서만 @ManyToOne으로 단방향 참조가 일어나는걸 볼 수 있습니다.

만약 자격증 엔터티에서만 학생엔터티를 참조를 하는 것이 아니라 학생 엔터티에서도 자격증 엔터티를 참조 하고싶은 경우에는 어떻게 해야될까요?!

단순합니다 양방향 참조를 하면됩니다. 예시를 같이 보시죠!

  • 학생엔터티
public class Student {
    @Id
    @Column(name = "StudentId")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long studentId;

    @Column
    private String name;
    
    @Column
    private String phoneNumber;
    
    @OneToMany(mappedBy = "student")
    private List<Certificate> certificates;

}
  • 자격증 엔터티
public class Certificate {
    @Id
    @Column(name = "Certificate_Id")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long certificateId;

    @Column
    private String certificateName;

    @ManyToOne(targetEntity = Student.class,fetch = FetchType.EAGER)
    @JoinColumn(name = "Student_Id")
    private Student student;

자 위를 보시면 학생 엔터티에서 @oneToMany를 이용하여 단방향 관게를 하나더 정해주었습니다. 그러면 이제 학생 엔터티에서도 자격증 엔터티를 참조를 가능하게 됩니다.

그러면 mappedBy는 뭘까요?!

두 객체(A, B)가 양방향 관계, 다시 말해 단방향 관계 2개(A→B, B→A)를 맺을 때, 연관 관계의 주인을 지정해야 합니다.

연관 관계의 주인을 지정 하는 것은 두 단방향 관계(A→B, B→A)중, 제어의 권한(외래 키를 비롯한 테이블 레코드를 저장, 수정, 삭제 처리)을 갖는 실질적인 관계가 어떤 것인지 JPA에게 알려준다고 생각하면 됩니다.

연관 관계의 주인은 연관 관계를 갖는 두 객체 사이에서 조회, 저장, 수정, 삭제를 할 수 있지만, 연관 관계의 주인이 아니면 조회만 가능합니다.

연관 관계의 주인이 아닌 객체에서 mappedBy 속성을 사용해서 주인을 지정해줘야합니다.

mappedBy로 지정할 때 값은 대상이 되는 변수명을 따라 지정하면 됩니다.

저는 그래서 student로 지정하였습니다.

이런 방식으로 데이터베이스 설계한 바탕으로 엔터티를 만들어서 @OneToMany @ManyToOne @OneToOne

사용해주시면 됩니다.

아 그리고 일대다(1:N) 단방향 연관 관계 매핑이 필요한 경우는 그냥 다대일(N:1) 양방향 연관 관계를 매핑해버리는게 추후에 유지보수에 훨씬 수월하기 때문에 이 방식을 채택하는 것을 추천한다고 하네요!

양방향 매핑 주의 할점

양방향 매핑을 하고 JSON타입을 변환할 경우에 infinite recursion이 일어날수도있습니다.

Jackson lib 의 ObjectMapper 객체에 의해 컨트롤러 단에서 JSON 타입을 변환하는 도중에 변환되는 엔티티의 필드가 다른 엔티티를 참조하고 그 엔티티 클래스의 필드가 또 다른 엔티티를 참조하고 ... 무한루프가 일어나게 됩니다.

저는 이방법을 통해서 해결했습니다!.

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=rorean&logNo=221593255071

좋은 웹페이지 즐겨찾기