Chapter6. 다양한 연관관계 매핑

김신영·2022년 11월 16일
0

JPA

목록 보기
4/14
post-thumbnail
post-custom-banner

연관관계 매핑시 고려사항

1. 다중성

  • @ManyToOne
  • @OneToMany
  • @OneToOne
  • @ManyToMany (@JoinTable )

2. 단방향, 양방향

  • @JoinColumn
  • @OneToMany(mappedBy = "")
  • @OneToOne(mappedBy = "")

3. 연관관계 주인

  • mappedBy
  • 외래키를 가진 Entity
  • 두 Entity 객체 연관관계 중 하나를 정해서 Database 외래키를 관리하는데, 그 Entity를 연관관계의 주인이라고 한다.

외래 키가 있는 쪽이 연관관계 주인이다.

연관관계 주인은 mappedBy 속성을 사용하지 않는다.

연관관계 주인이 아니면, mappedBy 속성을 사용해서 연관관계 주인의 필드 이름을 입력해야 한다.

@ManyToOne

1. 다대일 단방향

@Entity
@Table(name = "TEAM_MEMBER")
@Getter
@Setter
@NoArgsConstructor
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "MEMBER_ID")
    private Long id;

    @Column(name = "USERNAME")
    private String name;

    @ManyToOne
    @JoinColumn(name = "TEAM_ID")
    private Team team;
}
  • @JoinColumn(name = "TEAM_ID")
    • [Member.team](<http://Member.team>) 필드를 TEAM_ID 라는 컬럼으로 매핑
    • Team Entity 객체의 join column 설정

2. 다대일 양방향

  • 양방향은 외래 키가 있는 쪽이 연관관계의 주인이다.
@Entity
@Table(name = "TEAM_TABLE")
@Getter
@Setter
@NoArgsConstructor
public class Team {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
		//@Column(name = "TEAM_ID")
    private Long id;

    private String name;

    @OneToMany(mappedBy = "team")
    private List<Member> members = new ArrayList<>();
}

@OneToMany

1. 일대다 단방향

  • 반대편 테이블의 외래키를 매핑한다.
@Entity
@Table(name = "LEVEL")
@Getter
@Setter
public class Level {

    @Id @GeneratedValue
		@Column(name = "LEVEL_ID")
    private Long id;

    private String name;

    @OneToMany
    @JoinColumn(name = "LEVEL_ID") // MEMBER 테이블의 LEVEL_ID 컬럼
    private List<Member> memberList = new ArrayList<>();

    public void addMember(Member member) {
        memberList.add(member);
    }
}

일대다 단반향 단점

  • 해당 Entity가 INSERT 될 때, 외래키와 연관된 테이블 UPDATE 쿼리가 추가로 실행된다.
  • 일대다 단방향 매핑보다는 다대일 양방향 매핑을 권장한다.
Hibernate: 
    /* insert domain.team.Level
        */ insert 
        into
            LEVEL
            (name, LEVEL_ID) 
        values
            (?, ?)
Hibernate: 
    /* create one-to-many row domain.team.Level.memberList */ update
        MEMBER 
    set
        LEVEL_ID=? 
    where
        MEMBER_ID=?

2. 일대다 양방향

  • 다대일 양방향 매핑을 사용하는 것을 추천한다.
  • 양방향 매핑에서 @OneToMany 는 연관관계의 주인이 될 수 없다.
  • 단방향 매핑에서 @OneToMany 연관관계 주인이 될 수 있다.
  • [비추천] 일대다 단방향 매핑, 다대일 단방향 매핑(읽기 전용)
@Entity
@Table(name = "MEMBER")
@Getter
@Setter
@NoArgsConstructor
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "MEMBER_ID")
    private Long id;

    @Column(name = "USERNAME")
    private String name;

    @ManyToOne
    @JoinColumn(name = "LEVEL_ID", insertable = false, updatable = false)
    private Level level;
}

@OneToOne

1. 주 테이블에 외래키

@Entity
@Table(name = "MEMBER")
@Getter
@Setter
@NoArgsConstructor
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "MEMBER_ID")
    private Long id;

    @Column(name = "USERNAME")
    private String name;

    @OneToOne
    @JoinColumn(name = "LOCKER_ID")
    private Locker locker;
}
@Entity
@Table(name = "LOCKER")
@Setter
@Getter
@NoArgsConstructor
public class Locker {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "LOCKER_ID")
    private Long id;

    @Column
    private String name;

    @OneToOne(mappedBy = "locker")
    private Member member;
}

2. 대상 테이블에 외래키

JPA 2.0부터 일대다 단방향 관계에서 대상 테이블에 외래키가 있는 매핑을 허용한다.

하지만 일대일 단방향은 허용하지 않습니다.

@Entity
@Table(name = "MEMBER")
@Getter
@Setter
@NoArgsConstructor
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "MEMBER_ID")
    private Long id;

    @Column(name = "USERNAME")
    private String name;

    @OneToOne(mappedBy = "member")
    private LockerManager lockerManager;
}

@Entity
@Table(name = "LOCKER_MANAGER")
@Getter
@Setter
@NoArgsConstructor
public class LockerManager {
    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @OneToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;
}

@ManyToMany

1. 다대다 단반향

  • 관계형 데이터 베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없다.
  • @JoinTable , @ManyToMany
  • 연결 테이블로 매핑
@Entity
@Table(name = "MEMBER")
@Getter
@Setter
@NoArgsConstructor
public class Member {

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "MEMBER_ID")
    private Long id;

    @Column(name = "USERNAME")
    private String name;

		@ManyToMany
    @JoinTable(name = "MEMBER_PRODUCT",
        joinColumns = @JoinColumn(name = "MEMBER_ID"),
        inverseJoinColumns = @JoinColumn(name = "PRODUCT_ID"))
    private List<Product> productList = new ArrayList<>();
}

2. 다대다 양방향

@Entity
@Table(name = "PRODUCT_INFO")
@Getter
@Setter
public class Product {
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @ManyToMany(mappedBy = "productList")
    private List<Member> memberList = new ArrayList<>();
}
  • @JoinTable 을 통해 만들어진 연결 테이블은 JPA가 자동 생성한다.
  • 따라서 연결 테이블 상에서 컬럼 추가가 불가능하다. (실무에서 사용하기에 한계가 있다.)

3. 다대다: 연결 테이블 엔티티

  • 결국 연결 테이블을 직접 만들고, 이를 엔티티로 매핑시켜야 한다.
@Entity
@Table
@Getter
@Setter
public class MemberProduct {
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;

    @ManyToOne
    @JoinColumn(name = "PRODUCT_ID")
    private Product product;

    private Integer amount;

    private Integer price;
}
@Entity
@Table(name = "MEMBER")
@Getter
@Setter
@NoArgsConstructor
public class Member {
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "MEMBER_ID")
    private Long id;

    @Column(name = "USERNAME")
    private String name;

		@OneToMany(mappedBy = "member")
    private List<MemberProduct> memberProductList = new ArrayList<>();
}
@Entity
@Table(name = "PRODUCT")
@Getter
@Setter
@NoArgsConstructor
public class Product {

    @Id
    @GeneratedValue
    @Column(name = "PRODUCT_ID")
    private Long id;

    private String name;

    @OneToMany(mappedBy = "product")
    private List<MemberProduct> memberProductList = new ArrayList<>();
}

4. 다대다: 복합 기본키 활용

복합 기본키

  • 복합키는 별도의 식별자 클래스를 만들어야 한다.
  • Serializable 을 구현해야한다.
  • equals , hashCode 메소드를 구현해야 한다. (@EqualsAndHashCode )
  • 기본 생성자가 있어야 한다.
  • @IdClass , @EmbeddedId 활용
@Entity
@Table(name = "MEMBER_PRODUCT")
@IdClass(value = MemberProductId.class)
@Getter
@Setter
@NoArgsConstructor
public class MemberProduct {
    @Id
    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;

    @Id
    @ManyToOne
    @JoinColumn(name = "PRODUCT_ID")
    private Product product;

    private Integer amount;

    private Integer price;
}
@EqualsAndHashCode
@NoArgsConstructor
@AllArgsConstructor
public class MemberProductId implements Serializable {

    private Long member;

    private Long product;
}
profile
Hello velog!
post-custom-banner

0개의 댓글