Aggregate 관리 주체: Aggregate Root
다른 Aggregate를 참조한다 == 다른 Aggregate Root를 참조한다
Aggregate간 참조는 필드를 통해 구현한다
ex) 주문 Aggreagate에서 회원 Aggregate 참조
public class Orderer {
private Member member; // 회원 Aggregate 참조
private String name;
}
getter로 다른 Aggregate 데이터를 쉽게 가져올 수 있다.
하지만 다음과 같은 문제가 발생할 수 있다
쉽게 가져다 쓴다 ➡️ 쉽게 다른 Aggregate의 상태를 변경할 수 있다
Aggregate에서 다른 Aggregate의 상태를 변경하면 안된다! 내가 나의 상태를 바꿔야 한다.
왜? 상태를 변경한다는 것은 "의존" 이 생기기 때문
사실 실무에서 잘 안쓰지만 (우리회사에선 안씀) @ManyToOne, @OneToMany 를 사용하면 지연(lazy)로딩과 즉시(eager) 로딩 방식을 사용하게 된다.
다른 Aggregate에서 상태를 바꾸게 된다면 이러한 상황도 고려하여 로딩 전략을 결정해야 한다
모든 Aggregate이 같은 DBMS를 사용하지 않을 수 있다.
그런 경우 @ManyToOne, @OneToMany 요런 JPA로 데이터를 갖고오지 못할 수 있다.
ID값만 갖고 있고, 데이터를 가져올 때 ID값을 기반으로 데이터를 가져온다 (간접참조)
물리적 연결을 끊어 모델의 복잡도를 낮춰준다.
그리고, 의존을 제거하므로 응집도를 높여준다.
ex) 주문 Aggregate에서 회원 Aggregate 간접참조
public class Orderer {
private MemberId memberId; // 간접참조
private String name;
}
위에서 Aggregate마다 DBMS가 달라질 수 있다고 했는데 이때 한번의 쿼리로 관련 Aggregate 조회가 불가능하므로 캐시를 적용하거나, 조회 전용 저장소를 따로 구성한다.
코드는 복잡해지지만, 처리량은 높일 수 있다.
Aggregate간 1:N 혹은 N:M 연관이 있을 수 있다.
ex) 카테고리 - 상품
하나의 카테고리에 여러 상품이 속할 수 있다 ➡️ 카테고리 : 상품 = 1 : N
public class Category {
private Set<Product> products; // 상품 N
}
카테고리에 속한 상품 전체를 보여줄 수 있지만, 보통은 "페이징" 처리 하여 보여준다
public class Category {
private Set<Product> products; // 상품 N
public List<Product> getProducts (int page, int size) {
List<Product> sortedProducts = sortById(products);
return sortedProducts.subList((page - 1) * size, page * size);
}
}
➡️ 하지만 이 코드는 Set products를 위해 전체 products를 조회 해온다 (갯수가 많을 때 성능저하)
➡️ 그래서 1:N 연관이 있을 때 보통 실제 구현에 적용하지 않는다
그럼 어떻게 구현하죠? ➡️ 상품(Product)에 카테코리 ID 추가하기
public Class Product {
private CategoryId categoryId;
}
카테코리ID를 사용하여 Product를 조회한다.
N:M 연관일 경우엔?
public Class Product {
private Set<CategoryId> categoryIds;
}