양방향 @OneToMany 연관관계는 JPA(Java Persistence API)에서 부모 엔티티와 자식 엔티티 간의 일대다 관계를 설정할 때 사용된다. 이 관계를 효과적으로 구성하기 위해서는 여러 가지 고려사항이 있다.
1. 부모 측에서 전이 옵션을 사용해야 한다.
전이(cascading)는 항상 부모 엔티티가 자식 엔티티의 생명주기를 관리하도록 한다. 예를 들어, 부모 엔티티를 저장할 때 자식 엔티티도 함께 저장되도록 하려면 CascadeType.ALL 또는 필요한 전이 타입을 설정해야 한다.
@Entity
public class Parent {
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Child> children = new ArrayList<>();
}
2. 부모 측에 mappedBy를 지정한다.
부모 측에 설정된 mappedBy 속성으로 양방향 연관관계의 특성을 부여한다. 양방향 @OneToMany 연관관계에서 부모 측 @OneToMany에 mappedBy가 지정된다. mappedBy를 통해 양방향 @OneToMany가 자식 측 매핑을 미러링 한다는 표현을 한다.
@Entity
public class Child {
@ManyToOne
@JoinColumn(name = "parent_id")
private Parent parent;
}
3. 부모 측에 orphanRemoval을 지정한다.
orphanRemoval 속성을 true로 설정하면 부모 엔티티에서 자식 엔티티를 제거할 때 데이터베이스에서도 자식 엔티티가 삭제된다.
@Entity
public class Parent {
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Child> children = new ArrayList<>();
}
4. 연관관계의 양측을 부모 측 도우미 메서드를 이용해 동기화 상태로 유지시킨다.
부모 엔티티와 자식 엔티티 간의 연관관계를 설정할 때, 도우미 메서드를 사용하여 양측의 상태를 동기화하는 것이 좋다.
public void addChild(Child child) {
children.add(child);
child.setParent(this);
}
public void removeChild(Child child) {
children.remove(child);
child.setParent(null);
}
5. equals()와 hashCode()를 오버라이딩한다.
엔티티의 equals()와 hashCode() 메서드를 오버라이딩하여 엔티티의 동일성을 정의한다. 주로 자동 생성된 데이터베이스 식별자 필드를 기준으로 오버라이딩한다.
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Parent parent = (Parent) o;
return Objects.equals(id, parent.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
6. 연관관계 양측에서 지연 로딩을 사용한다.
지연 로딩(Lazy Loading)을 사용하면 실제로 필요한 시점에만 데이터를 로딩하여 성능을 최적화할 수 있다.
7. toString() 오버라이딩 방법에 주의한다.
toString() 메서드를 오버라이딩할 때 연관관계 필드를 포함하면 별도 SQL문 실행 또는 순환 참조 문제가 발생할 수 있다. 따라서 연관관계 필드를 제외하거나 적절히 처리해야 한다. 데이터베이스에 있는 기본 속성만 포함하는 게 좋다. Lombok 라이브러리 사용보다는 직접 정의하는 게 좋다.
@Override
public String toString() {
return "Parent{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
8. @JoinColumn을 사용해 조인 컬럼을 명시적으로 지정한다.
@JoinColumn을 사용하여 외래 키 컬럼의 이름을 명시적으로 지정할 수 있다. 이는 데이터베이스 스키마를 명확하게 정의하는 데 도움이 된다.
@Entity
public class Child {
@ManyToOne
@JoinColumn(name = "parent_id")
private Parent parent;
}
9. Cascade.REMOVE 옵션을 통한 엔터티 삭제 처리에 주의한다.
여러 엔터티를 삭제하는 경우 다량의 SQL문이 발생할 수 있다. 한 번에 삭제가 가능한 벌크 처리를 사용하는 것이 좋다.
결론
@OneToMany 연관관계를 효과적으로 구성하기 위해서는 위에서 설명한 여러 가지 고려사항을 종합적으로 적용해야 한다. 이를 통해 데이터의 일관성을 유지하고 성능을 최적화할 수 있다. JPA를 사용한 엔티티 설계는 복잡할 수 있지만, 이러한 원칙을 잘 이해하고 적용하면 보다 안정적이고 효율적인 애플리케이션을 개발할 수 있다.
'Spring > JPA' 카테고리의 다른 글
@ManyToOne 연관관계에서 부모 엔터티를 등록할 때 프록시 호출을 통해 JPA 최적화 하기 (0) | 2024.10.22 |
---|---|
CascadeType.REMOVE, orphanRemoval=true 특징 (1) | 2024.10.20 |
JPA Buddy 플러그인을 이용해서 엔티티에 equals와 hashcode를 명시적으로 구현해야 하는 이유 (0) | 2024.06.22 |
[Querydsl] @OneToMany에서 조건 절과 Fetch Join을 함께 사용할 때 서브쿼리 사용하기 (0) | 2024.05.12 |
@Lob 사용시 DB와 엔티티 필드 타입이 다른 경우 발생하는 문제와 해결방법 (0) | 2024.01.07 |
댓글