
위의 이미지와 같은 구조의 테이블을 JPA Entity로 지정해봅시다
우선 grand_parent 테이블 엔티티는 간단하게 구성할 수 있습니다
@Entity
public class GrandParent {
@Id
@Column(name= "grand_parent_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long grandParentId;
@Column(name= "grand_parent_name", nullable = false)
private String grandParentName;
}
다음으로 parent 테이블 엔티티를 구성해봅시다. @IdClass를 이용하여 구성할건데 이전글
2023.02.19 - [Spring] - [Spring JPA] 복합키 적용하는 방법을 참조하여 구성하시면 됩니다.
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@NoArgsConstructor
@AllArgsConstructor
public class ParentPK implements Serializable {
@EqualsAndHashCode.Include
private Long parentId;
@EqualsAndHashCode.Include
private Long grandParent;
}
@IdClass(ParentPK.class)
@Entity
public class Parent {
@Id
@Column(name= "parent_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long parentId;
@Id
@ManyToOne
@JoinColumn(name = "grand_parent_id")
private GrandParent grandParent;
@Column(name= "parent_name", nullable = false)
private String parentName;
}
Entity에는 @JoinColumn에 @Id 어노테이션을 추가합니다. 그리고 중요한 IdClass에서 JoinColum의 객체와 동일한 이름으로 하고 다만 타입은 해당 엔티티의 PK타입으로 지정해야 합니다.
다시말해 GrandParent 엔티티의 PK가 Long타입이므로 IdClass에서 grandParent 필드의 타입은 Long으로 지정하였습니다
다음으로 Child 엔티티를 구성해봅니다. 이전에 하던 규칙과 동일하게 하면됩니다. 다만 JoinColumn자체가 복합키로 이루어지므로 @JoinColumns로 구성되는 부분을 체크해주세요
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@NoArgsConstructor
@AllArgsConstructor
public class ChildPK implements Serializable {
@EqualsAndHashCode.Include
private Long childId;
@EqualsAndHashCode.Include
private ParentPK parent;
}
@IdClass(ChildPK.class)
@Entity
public class Child {
@Id
@Column(name= "child_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long childId;
@Id
@ManyToOne
@JoinColumns({
@JoinColumn(name = "grand_parent_id"),
@JoinColumn(name = "parent_id")
})
private Parent parent;
@Column(name= "child_name", nullable = false)
private String childName;
}
Parent 엔티티의 PK가 ParentPK타입이므로 IdClass에서 parent 필드의 타입은 ParentPK으로 지정하였습니다. 그리고 앞서 말한대로 @JoinColumns를이용하여 복합키를 JoinColum으로 지정하면 첫 페이지의 이미지와 같은 테이블 구성을 할수 있습니다
IdClass에서 @EqualsAndHashCode.Include 를 사용하는 이유?
@IdClass는 복합 기본 키(composite primary key)를 지원하기 위해 사용되는 애노테이션입니다. 이 애노테이션은 엔티티 클래스에서 복합 기본 키를 구성하는 여러 필드를 지정할 수 있도록 해줍니다.
하지만, @IdClass를 사용할 때는 반드시 @EqualsAndHashCode 애노테이션과 함께 @EqualsAndHashCode.Include 애노테이션을 사용해야 합니다. 이는 equals()와 hashCode() 메서드를 구현할 때 복합 기본 키를 모두 고려하여 구현할 수 있도록 해주기 때문입니다.
만약 @EqualsAndHashCode.Include 애노테이션을 사용하지 않는다면, equals()와 hashCode() 메서드에서 복합 기본 키 중 일부만을 고려하고 다른 필드를 고려하지 않을 수 있습니다. 이 경우 equals()와 hashCode() 메서드를 사용할 때 예상치 못한 결과가 발생할 수 있으며, 이로 인해 프로그램의 오작동을 유발할 수 있습니다.
따라서, @IdClass를 사용할 때는 반드시 @EqualsAndHashCode 애노테이션과 함께 @EqualsAndHashCode.Include 애노테이션을 사용하여 모든 복합 기본 키 필드를 고려하도록 해야 합니다.
IdClass에서 Serializable을 impliments 하는 이유?
@IdClass를 사용하여 복합 기본 키(composite primary key)를 지정하는 경우, 엔티티 클래스에는 복합 기본 키를 구성하는 여러 필드가 포함됩니다. 이러한 필드를 직렬화(serialization)할 수 있도록 Serializable 인터페이스를 구현해야 합니다.
Serializable 인터페이스를 구현함으로써 객체를 이진 형식으로 직렬화하고, 전송하거나 저장할 수 있습니다. 따라서, 엔티티 클래스에 Serializable 인터페이스를 구현하지 않으면, 복합 기본 키를 포함하는 객체를 직렬화할 수 없으며, 이는 객체를 전송하거나 저장하는 데 문제를 일으킬 수 있습니다.
또한, JPA에서는 엔티티 클래스를 직렬화해야 하는 경우가 있습니다. 예를 들어, 분산 캐싱(distributed caching)을 사용하거나 JPA 엔티티를 RMI(Remote Method Invocation)로 노출해야 할 경우에는 Serializable 인터페이스를 구현해야 합니다.
따라서, @IdClass를 사용하여 복합 기본 키를 지정하는 엔티티 클래스에서는 Serializable 인터페이스를 구현해야 합니다.
'Spring' 카테고리의 다른 글
[Spring JPA] Executing an update/delete query (0) | 2023.04.28 |
---|---|
[Spring] DTO에 @Builder 사용시 JSON parse error: Cannot construct instance of 에러 발생하는 이유 (0) | 2023.04.04 |
Gradle (0) | 2023.03.29 |
[Spring] mapStruct에서 LocalDateTime을 epoch Milli로 변경하는 방법 (0) | 2023.03.24 |
[Spring] 조회메서드에 @Transactional(readOnly=true)를 사용해야하는 이유 (0) | 2023.03.23 |
댓글