@EmbeddedId를 사용하면 좀 더 객체지향적인 코드를 작성할 수 있다.
[Parent]
@Entity
public class Parent {
@EmbeddedId
private ParentId parentId;
private String name;
}
@Embeddable
public class ParentId implements Serializable {
@Column(name = "PARENT_ID1")
private String parentId1;
@Column(name = "PARENT_ID2")
private String parentId2;
}
@IdClass
로 식별자 클래스 사용시에는 복합키의 속성들을 모두 열거했었다.
하지만 @EmbeddedId
를 이용하면 엔티티에 식별자 클래스형만 명시하면 된다.
식별자 클래스에는 @Embeddable
어노테이션을 붙여준다.
그리고 식별자 클래스 조건은 @IdClass
와 동일하다.
public static void save(EntityManger em) {
ParentId parentId = new ParentId("PARENT#1", "PARENT#2");
Parent parent = new Parent();
parent.setParentId(parentId);
parent.setName("NAME#1");
em.persist(parent);
}
조회하는 코드는 @IdClass
와 같다. 저장시 코드가 달라지는데 좀 더 객체지향적인 코드를 작성할 수 있다는 점이 드러난다. @IdClass
는 Parent 객체의 parentId1, parentId2를 set하면 영속화시킬 때 내부적으로 ParentId를 이용한다고 했었다. 그런데 @EmbeddedId
를 이용하면 저장시 ParentId를 명시적으로 이용한다.
Serializable
은 직역하면 직렬화를 한다는 의미이다. 직렬화란 객체 또는 데이터를 자바 시스템 외에서도 사용할 수 있도록 Byte 형태로 변환하는 기술이다. (JSON이 대표적인 예시)
Java에서 객체를 참조할 때 주소값을 참조한다. 만약 이를 DB에 저장한다고 가정해보자. 어플리케이션을 재시작하면 이 주소값은 아무런 의미가 없다. 식별자 클래스의 정보를 직렬화하여 DB의 올바른 컬럼에 올바른 값들을 저장하고 나중에 조회할 때도 역직렬화하여 식별자 클래스 객체를 생성해야 하므로 Serializable
은 필요하다.
ParentId id1 = new ParentId();
id1.setId1("myId1");
id1.setId2("myId2");
ParentId id2 = new ParentId();
id2.setId1("myId1");
id2.setId2("myId2");
id1.equals(id2) -> ?
위의 경우 JPA에서id1
과 id2
가 같다고 판단해야 해당 식별자 객체로 검색한 엔티티가 같은 엔티티임을 보장할 수 있다. 그래서 eqauls와 hashCode를 재정의 해야한다.