CQRS를 사용하여 도메인을 구현하는 상당한 규모의 커뮤니티가 있습니다. 내 저장소의 인터페이스가 사용 된 모범 사례와 유사하다면 너무 길을 잃지 않을 것이라고 생각합니다.
내가 본 것을 바탕으로 ...
1) 명령 핸들러는 일반적으로 저장소를 사용하여 저장소를 통해 집계를로드합니다. 명령은 집계의 단일 특정 인스턴스를 대상으로합니다. 저장소는 ID별로 루트를로드합니다. 내가 볼 수있는 것은 아니지만 집계 컬렉션에 대해 명령이 실행되는 경우는 없습니다 (대신 먼저 집계를 수집하기 위해 쿼리를 실행 한 다음 컬렉션을 열거하고 각각에 명령을 발행합니다).
따라서 집계를 수정하려는 컨텍스트에서 저장소가 엔티티 (일명 집계 루트)를 반환 할 것으로 기대합니다.
2) 쿼리 핸들러는 집계를 전혀 건드리지 않습니다. 그 대신, 특정 시점에서 집계 / 집계의 상태를 설명하는 가치 개체 인 집계의 투영을 처리합니다. 따라서 AggregateDTO가 아니라 ProjectionDTO를 생각하면 올바른 아이디어가 있습니다.
집계에 대해 쿼리를 실행하고 표시를 준비하는 등의 컨텍스트에서 엔터티가 아닌 DTO 또는 DTO 컬렉션이 반환 될 것으로 기대합니다.
귀하의 모든 getCustomerByProperty
전화는 나에게 질문처럼 보이므로 후자의 범주에 속합니다. 컬렉션을 생성하기 위해 단일 진입 점을 사용하고 싶을 수도 있으므로
getCustomersThatSatisfy(Specification spec)
합리적인 선택입니다. 그런 다음 쿼리 핸들러는 제공된 매개 변수에서 적절한 사양을 구성하고 해당 사양을 리포지토리에 전달합니다. 단점은 서명이 리포지토리가 메모리의 컬렉션임을 실제로 제안한다는 것입니다. 저장소가 관계형 데이터베이스에 대해 SQL 문을 실행하는 추상화 일 경우 술어가 많은 것을 구매한다는 것은 분명하지 않습니다.
그래도 도움이 될 수있는 몇 가지 패턴이 있습니다. 예를 들어, 사양을 직접 작성하는 대신, 제한 조건에 대한 설명을 저장소에 전달하고 저장소 구현이 수행 할 조치를 결정하도록 허용하십시오.
경고 : 입력과 같은 자바 감지
interface CustomerRepository {
interface ConstraintBuilder {
void setLastName();
void setFirstName();
}
interface ConstraintDescriptor {
void copyTo(ConstraintBuilder builder);
}
List<CustomerProjection> getCustomersThatSatisfy(ConstraintDescriptor descriptor);
}
SQLBackedCustomerRepository implements CustomerRepository {
List<CustomerProjection> getCustomersThatSatisfy(ConstraintDescriptor descriptor) {
WhereClauseBuilder builder = new WhereClauseBuilder();
descriptor.copyTo(builder);
Query q = createQuery(builder.build());
//...
}
}
CollectionBackedCustomerRepository implements CustomerRepository {
List<CustomerProjection> getCustomersThatSatisfy(ConstraintDescriptor descriptor) {
PredicateBuilder builder = new PredicateBuilder();
descriptor.copyTo(builder);
Predicate p = builder.build();
// ...
}
class MatchLastName implements CustomerRepository.ConstraintDescriptor {
private final lastName;
// ...
void copyTo(CustomerRepository.ConstraintBuilder builder) {
builder.setLastName(this.lastName);
}
}
결론 : 집합체 제공과 DTO 제공 사이의 선택은 소비자가 소비자와 함께 할 것으로 기대하는 것에 달려 있습니다. 내 생각에는 각 컨텍스트에 대한 인터페이스를 지원하는 하나의 구체적인 구현 일 것입니다.
GetCustomerByName('John Smith')
데이터베이스에 당신이 스무 존 스미스가있는 경우 반환? 두 사람이 같은 이름을 가지고 있지 않다고 가정합니다.