복합 키를 사용하기 위한 식별자 클래스를 지정하는 데 사용한다.
특징
- Serializable을 구현해야 한다.
- equals와 hashCode 메소드를 구현해야 한다.
- 기본 생성자가 있어야 한다.
- 식별자 클래스는 public이어야 한다.
- 복합 키에는 @GenerateValue를 사용할 수 없다. 복합 키를 구성하는 여러 컬럼 중 하나에도 사용할 수 없다.
아래 두 예제 코드는 식별 관계를 예로 들고 있다.
매핑도 쉽고 코드도 단순하고 복합 키도 필요 없는 비식별 관계를 사용하자.
그럴듯 해 보이는 것이 항상 문제를 만든다.
@IdClass
@Entity
@IdClass(OrderID.class)
public class Order {
@Id
@ManyToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
@Id
@ManyToOne
@JoinColumn(name = "PRODUCT_ID")
private Product product;
private int orderAmount;
}
public class OrderId implements Serializable {
private String member; // 속성명이 같아야 한다.
private String product;
@Override
public boolean equals(Object o) {...}
@Override
public int hashCode() {...}
}
// 저장하는 코드
public void save(){
Member member = new Member();
member.setId("member");
em.persist(member);
Product product = new Product();
product.setId("product");
em.persist(product);
Order order = new Order();
order.setMember(member);
order.setProduct(product);
order.setOrderAmount(2);
em.persist(order);
}
// 조회하는 코드
public void find() {
Order order = new Order();
order.setMember("memberId");
order.setProduct("productId");
Order order = em.find(Order.class, order);
Member member = memberProduct.getMember();
Product product = memberProduct.getProduct();
}
복합키를 사용하는 테이블과 비식별 관계인 테이블을 매핑할 경우
@Entity
public class OrderChild {
@Id
private String id;
@ManyToOne
@JoinColumns({
@JoinColumn (name = "MEMBER_ID",
referecedColumnName = "MEMBER_ID"),
@JoinColumn (name = "PRODUCT_ID",
referecedColumnName = "PRODUCT_ID"),
})
private Order order;
}
@EmbeddedId
@IdClass에 비해 객체지향적이고 중복도 없지만 특정 상황에 JPQL이나 코드가 조금 더 길어질 수 있다.
@Entity
public class Parent {
@Id @Column(name = "PARENT_ID")
private String id;
private String name;
}
@Entity
public class Child {
@EmbeddedId
private ChildId id;
@MapsId("parentId") // ChildId.parentId 매핑
@ManyToOne
@JoinColumn(name = "PARENT_ID")
public Parent parent;
private String name;
}
@Embeddable
public class ChildId implements Serializable {
public String parentId; // @MapsId("parentId")로 매핑
@Column(name = "CHILD_ID")
private String id;
// equals, hashCode
}
@Entity
public class GrandChild {
@EmbeddedId
private GrandChildId id;
@MapsId("childId") // GrandChildId.childId 매핑
@ManyToOne
@JoinColumns({
@JoinColumn(name = "PARENT_ID"),
@JoinColumn(name = "CHILD_ID")
})
public Child child;
private String name;
}
@Embeddable
public class GrandChildId implements Serializable {
public ChildId childId; // @MapsId("childId")로 매핑
@Column(name = "GRANDCHILD_ID")
private String id;
// equals, hashCode
}
복합 키와 equals(), hashCode()
영속성 컨텍스트는 엔티티의 식별자를 키로 사용해서 엔티티를 관리한다. 그리고 식별자를 비교할 때 equlas()와 hashCode()를 사용한다. 따라서 식별자 객체의 동등성(equals 비교)이 지켜지지 않으면 예상과 다른 엔티티가 조회되거나 엔티티를 찾을 수 없는 등 영속성 컨텍스트가 엔티티를 관리하는 데 심각한 문제가 발생한다.
복합키 엔티티의 equals() 를 오버라이드 하지 않았다면 Object 클래스의 equals()를 사용해서 인스턴스를 비교하는데 Object.equals 는 기본적으로 인스턴스 참조 값만을 비교한다.
728x90
'JVM > JPA' 카테고리의 다른 글
@MappedSuperclass (0) | 2023.06.17 |
---|---|
상속 관계 매핑 (슈퍼-서브 타입 모델링) (0) | 2023.06.17 |
@ManyToMany (0) | 2023.06.16 |
@OneToOne (0) | 2023.06.16 |
@OneToMany (0) | 2023.06.12 |