티스토리 뷰

다대일[N:1]

다대일 단방향

회원 엔티티

@Entity
public class Member {

    @Id
    @Column(name = "member_id")
    @GeneratedValue
    private Long id;
    @ManyToOne
    @JoinColumn(name = "team_id")
    private Team team;
}

팀 엔티티

@Entity
public class Team {

    @Id
    @Column(name = "team_id")
    @GeneratedValue
    private Long id;
    private String name;
}
  • @ManyToOne 어노테이션을 사용하여 다대일 단방향 매핑
  • @JoinColumn 어노테이션을 사용하여 회원 테이블의 Team_Id와 회원 엔티티의 team 필드를 매핑

 

다대일 양방향

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

 

  • 팀 엔티티에 @OneToMany 어노테이션을 추가하여 양방향 매핑 
  • mappedBy 속성을 사용하여 연관관계 주인 설정 
    • 양방향은 항상 외래키가 있는 쪽이 연관관계의 주인이다 
    • 양방향 연관관계는 항상 서로를 참조해야한다

 

일대다[1:N]

일대다 단방향

@Entity
public class Team {

    @Id
    @Column(name = "team_id")
    @GeneratedValue
    private Long id;
    private String name;
    @OneToMany
    @JoinColumn(name = "team_id")
    private List<Member> mebers = new ArrayList<>();
}
  • @JoinColumn을 반드시 사용해야한다.
    • 반대편 테이블의 외래키를 관리하기 때문 
    • 그렇지 않으면 중간에 테이블을 하나 추가하는 조인 테이블 방식을 사용한다.
  • 1:N 단방향의 매핑의 단점
    • 엔티티가 매핑한 외래키가 다른 테이블에 있기 때문에 발생한다
    • 다른 테이블에 외래키가 있으므로 연관관계 처리를 위한 Update SQL을 추가로 실행해야한다 
    • 때문에 성능 문제가 발생하고 관리도 어려워진다
    • 일대다 단방향 매핑보단 다대일 양방향 매핑을 권장한다

 

일대다 양방향

사실상 일대다 양방향 매핑은 존재하지 않는다(@OneToMany는 주인이 될 수 없다)

@ManyToOne
@JoinColumn(insertable = false, updatable = false)
private Team team;
  • 일대다 매핑 반대편에 같은 외래 키를 사용하는 다대일 단방향 매핑을 읽기 전용으로 추가하여 양방향처럼 보이게 할 수 있다
  • 하지만 일대다 단방향 매핑이 가지는 단점을 그대로 가지므로 다대일 양방향 매핑을 권장한다. 

 

일대일[1:1]

  • 주 테이블이나 대상 테이블 중 어느곳에 외래키를 둘것인지 선택해야 한다.
  • 외래키에 데이터베이스 유니크 제약 조건을 추가해야 한다.

 

주 테이블에 외래키가 있는 경우

일대일 단방향

회원 엔티티

@Entity
public class Member {

    @Id
    @Column(name = "member_id")
    @GeneratedValue
    private Long id;
    
    private string username;
    
    @OneToOne
    @JoinColumn(name = "locker_id")
    private Locker locker;
}

 

락커 엔티티

@Entity
public class Locker {

    @Id
    @Column(name = "locker_id")
    @GeneratedValue
    private Long id;
    
    private String name;
}
  • 회원 테이블(= 주 테이블)의 외래키 locker_id와 locker 필드 매핑
  • 다대일 단방향과 비슷한 형태

 

일대일 양방향

@OneToOne(mappedBy = "locker")
private Member member;
  • 반대 엔티티에 @OneToOne 어노테이션 추가후 mapped by 속성을 통해 연관관계 주인 설정

 

대상 테이블에 외래키가 있는 경우

일대일 단방향

단방향 관계는 지원하지 않는다

 

일대일 양방향

@OneToOne
@JoinColumn(name = "Member_id")
private Member member;
@OneToOne(mapped by = "member")
private Locker locker;
  • 일대일 주 테이블에 외래키 양방향 매핑과 방법이 같다
  • 외래키의 위치가 뒤바뀜에 따라 연관관계의 주인도 반대로 뒤바껴진다
  • 프록시를 사용할 때 외래 키를 직접 관리하지 않는 일대일 관계는 즉시 로딩된다 
    • 1:N의 경우 배열의 형태로 프록시를 감싸기 때문에 문제가 없지만
    • 1:1은 객체가 null인 경우 null을 프록시로 감쌀 수 없기 때문

 

다대다[N:N]

  • 관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없다
  • 그래서 중간에 연결 테이블을 추가하여 일대다, 다대일 관계로 풀어내야 한다
  • 객체는 테이블과 다르게 객체 2개로 다대다 관계를 만들 수 있다

다대다 단방향

@Entity
public class Member {

    @Id
    @GeneratedValue
    @Column(name = "member_id")
    private Long id;
    
    @ManyToMany
    @JoinTable(name = "member_product",
    	joinColumns = @JoinColumn(name = "member_id"),
        inverseJoinColumns = @JoinColumn(name = "product_id"))
    private List<Product> productList = new ArrayList<>();
    
 }
  • @JoinTable 어노테이션을 사용하여 연결 테이블을 매핑해준다

다대다 양방향

@Entity
public class Product {

    @Id
    @GeneratedValue
    @Column(name = "product_id")
    private Long id;
    
    @ManyToMany(mappedBy = "productList")
    private List<Member> memberList = new ArrayList<>();
    
}
  • 반대도 @ManyToMany 어노테이션을 통해 매핑하고 mapped by 속성을 통해 연관관계 주인을 지정한다

 

다대다에서의 연결 엔티티 사용

복잡한 비즈니스 로직으로 인해 연결 테이블에 칼럼을 추가하게 되면 @ManyToMany를 사용할 수 없게 된다.

왜냐면 각 회원, 상품 엔티티에서 추가한 칼럼들을 매핑할 수 없기 때문이다. 이러한 문제를 해결하기 위해선 연결 테이블에 대한 

연결 엔티티를 만들고 엔티티 간의 관계를 다대일, 일대다 관계로 풀어야 한다.

 

이때 연결 엔티티의 기본키 생성 전략이 두가지가 있다

  • 복합 기본 키 사용
  • 새로운 기본 키 사용

 

복합 기본 키를 사용한 연결 엔티티 생성

 

회원 엔티티

@Entity
public class Member {

    @Id
    @GeneratedValue
    @Column(name = "member_id")
    private Long id;
    
    private String memberName;
    
    @OneToMany(mappedBy = "member")
    private List<MemberProduct> memberProductList
    
 }

상품 엔티티

@Entity
public class Product {

    @Id
    @GeneratedValue
    @Column(name = "product_id")
    private Long id;
    
    private String productName;
    
    @OneToMany(mappedBy = "product")
    private List<MemberProduct> memberProductList
      
}

회원-상품 엔티티 (연결 엔티티)

@Entity
@IdClass(MemberProductId.class)
public class MemberProduct {

    @Id
    @ManyToOne
    @JoinColumn(name = "member_id")
    private Member member;
    
    @Id
    @ManyToOne
    @JoinColumn(name = "product_id")
    private Product product;
    
    private int orderAmount;
    private LocalDate orderDate;
    
}
  • 회원 엔티티와 연결 엔티티를 일대다, 다대일 양방향 관계로 풀어주었다
  • 상품 엔티티에서 객체 그래프 탐색이 필요 없을 것을 예상하여 관계를 없애주었다
  • 연결 엔티티에서 복합 기본 키를 사용하여 기본 키를 매핑했다
    • 기본 키를 매핑하는 @Id와 외래 키를 매핑하는 @joinColumn을 동시에 사용하여 기본키 + 외래키를 한번에 매핑
    • @IdClass를 사용해서 복합 기본 키를 매핑

 

새로운 기본 키를 사용한 연결 엔티티 생성

회원 엔티티

@Entity
public class Member {

    @Id
    @GeneratedValue
    @Column(name = "member_id")
    private Long id;
    
    private String memberName;
    
    @OneToMany(mappedBy = "member")
    private List<MemberProduct> memberProductList
    
 }

상품 엔티티

@Entity
public class Product {

    @Id
    @GeneratedValue
    @Column(name = "product_id")
    private Long id;
    
    private String productName;
    
    @OneToMany(mappedBy = "product")
    private List<MemberProduct> memberProductList
      
}

회원-상품 엔티티(연결 엔티티)

@Entity
public class MemberProduct {

    @Id
    @GeneratedValue
    @Column(name = "order_id")
    private Long id;
    
    @ManyToOne
    @JoinColumn(name = "member_id")
    private Member member;
    
    @ManyToOne
    @JoinColumn(name = "product_id")
    private Product product;
    
    private int orderAmount;
    private LocalDate orderDate;
    
}
  • 대리키를 사용함으로써 앞의 복합 키를 사용하는 것보다 매핑이 단순해진다
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함