2017-05-17 10 views
0

일부 비즈니스 메소드를 호출해야 할 때, 작업이 아래에 주어진 것과 같은 프리미티브 (컬렉션에 항목을 추가하는 것) 일지라도 작업과 관련된 모든 집계 루트를 가져와야합니다. 내가 뭘 놓치고 있니? 또는 테이블 조인을 포함하여 하나의 쿼리를 실행하고 마지막에 선택하고 삽입하는 CRUD 기반 접근 방식이며 데이터베이스 엔진이 모든 작업을 실제로 수행합니다. 실제로 성능면에서 더 낫습니다.DDD로 여러 집계를 효율적으로 쿼리하는 방법은 무엇입니까?

아래 코드에서 별도의 집계 루트 (다른 ​​데이터베이스 연결을 만들고 다른 선택 쿼리를 보냄)를 쿼리해야합니다. 실제 응용 프로그램에서는 단일 비즈니스 조치에 대해 최대 8 개 이상의 단일 집계를 쿼리했습니다. 성능/쿼리 오버 헤드를 어떻게 줄일 수 있습니까?

도메인 집계 뿌리 :

class Device 
{ 
    Set<ParameterId> parameters; 

    void AddParameter(Parameter parameter) 
    { 
     parameters.Add(parameter.Id); 
    } 
} 

class Parameter 
{ 
    ParameterId Id { get; } 
} 

응용 프로그램 계층 :

class DeviceApplication 
{ 
    private DeviceRepository _deviceRepo; 
    private ParameterRepository _parameterRepo; 

    void AddParameterToDevice(string deviceId, string parameterId) 
    { 
     var aParameterId = new ParameterId(parameterId); 
     var aDeviceId = new DeviceId(deviceId); 

     var parameter = _parameterRepo.FindById(aParameterId); 
     if (parameter == null) throw; 

     var device = _deviceRepo.FindById(aDeviceId); 
     if (device == null) throw; 

     device.AddParameter(parameter); 
     _deviceRepo.Save(device); 
    } 
} 

가능한 해결 방법 난 당신이 같은 다른 골재 단지 ID를 전달할 수 있다는 들었다

:

class Device 
{ 
    void AddParameter(ParameterId parameterId) 
    { 
     parameters.Add(parameterId); 
    } 
} 

하지만 IMO는 (비즈니스에 용어 ID를 명시 적으로 강조하여) 인 캡슐 레이션을 중단하고 잘못된 (사용자가 만든) 잘못된 ID를 붙여 넣는 것을 막지 않습니다.

Vaughn Vernon은 첫 번째 방법 (전체 집계 인스턴스 전달)을 사용하는 응용 프로그램 서비스의 예를 제공합니다.

+0

직접 집계하지 않고 IDS를 직접 추가/삭제할 수 있습니까? – EwanCoder

답변

2

짧은 대답은 - 집계를 전혀 쿼리하지 않습니다.

집계는 데이터가 아닌 동작을 노출하는 모델입니다. 일반적으로 집계에 getter를 사용하는 코드 냄새로 간주됩니다 (ID는 예외 임). 이것은 약간의 질의를하게 만듭니다.

대체로 말해서이 문제를 해결하는 두 가지 방법이 있습니다. 아마 더 많은 것들이 있지만 적어도 이것들은 캡슐화를 깨뜨리지 않습니다.

옵션 1 : 도메인 이벤트 사용 - 내부 상태에 대한 변경 사항을 보여주는 이벤트를 내보내는 도메인 (집계 루트)을 얻음으로써 쿼리를 위해 특별히 설계된 데이터베이스에 테이블을 구축 할 수 있습니다. 필요하다면 직선적으로 스케일 될 수있는 높은 성능의 비정규 화 된 질의 가능한 데이터를 갖게 될 것입니다. 이것은 매우 간단한 쿼리를 만듭니다. 이 블로그 게시물의 예가 있습니다 : How to Build a Master-Details View when using CQRS and Event Sourcing

옵션 2 : 쿼리 테이블을 추측합니다 - 저는 옵션 1을 매우 좋아합니다. 그러나 이벤트 소스 접근 방식이 없다면 계속 사용해야합니다. 어느 시점에서 집계 상태. 이를 수행하는 데는 여러 가지 방법이 있지만 수집을 위해 지속성 파이프 라인에 연결할 수 있으므로 쿼리에 사용할 쿼리 가능 데이터를 읽기 모델로 추출 할 수 있습니다.

나는 그것이 의미가 있기를 바랍니다.

+0

도메인 이벤트를 사용하고 별도의 읽기 모델/CQRS 패턴을 사용하고 있습니다. 그러나 DOMAIN 액션을 수행하기 위해서는 ID를 얻기 위해 집계를 쿼리해야합니다. 아니면 비즈니스 메소드가 집계 루트 대신 ID를 사용해야한다고 제안 하시겠습니까? (하지만, 나는 도메인 객체 상태를 저장하고 있으므로 쿼리 할 필요가 있습니다. 결국 잠재적으로 일관성있는 일부 읽기 모델이 아닙니다.) – EwanCoder

+0

예 - 이미 읽은 모델의 ID를 알고 있어야합니다. – Codescribler

+0

그래서 장치에 일부 매개 변수를 추가해야 할 때 장치에는 매개 변수 자체가 아닌 ParameterId를 허용하는 메서드가 있어야합니다. 그건 본 버논이 한 일이 아닙니다. 현재 내 장치에는 매개 변수 자체를 허용하는 메서드가 있으며 내부에는 ID를 묻고 저장합니다. – EwanCoder

0

조인이있는 RDBMS 쿼리가이 경우 작동한다는 것을 알았다면 아마도 잘못된 집계 경계를 가졌을 것입니다.

예를 들어 Device에 추가하려면 Parameter을로드해야하는 이유는 무엇입니까?이 ID는 이미 Parameter이며,이 ID를 Device의 참조 목록 Parameters 목록에 추가하기 만하면됩니다. ORM을 만족 시키려면이 작업을 수행하는 것이 가장 좋을 것입니다.

총계 은 트랜잭션 경계 인입니다. 하나의 트랜잭션과 하나의 연결 내에서 모든 데이터베이스 작업을 완료하려고합니다.

+0

네, 맞습니다. 나는 이드를 가지고 있는데이 이드를 이드의 목록에 추가 할 수있다. AddParameter 메서드가 매개 변수 집계 루트 (ParameterId 값 개체 아님)를 수락하여 집계 간의 밀집과 밀집성을 유지하는 것입니다. 그리고 이것은 다른 집단을 모을 필요성을 불러옵니다. (나중에 ID를 얻는 것). – EwanCoder

+1

값 개체를 ID로 사용하여 충분히 캡슐화 할 수 있으므로'ParameterId' 개체 (struct)를 전달하지만 완벽하게 유효합니다. 미리 가져온 집계를 전달할 필요가 없습니다. 집계에는 ID 이외의 다른 유형의 참조가 전혀 없다는 것이 분명합니다. –

+0

캡슐화 란 비즈니스 논리를 의미합니다 (매개 변수를 장치로 전달하고 매개 변수는 장치로 전달하지 않음). 모든 종류의 ID는 비즈니스가 ID에 신경 쓰지 않기 때문에 약간의 캡슐화 중단입니다. 그리고 이미 ID에 값 객체를 사용하고 있습니다. 어쨌든, 우리가'ParameterId' 객체를 전달하면 또 다른 문제가 발생합니다 : 사용자가 임의의 ParameterId 객체 또는 유효하지 않은 ParameterId 객체 또는 이미 삭제 된 집계의 ID를 생성하면 어떨까요? 이것은 집계 자체를 전달할 때 자동으로 방지됩니다. – EwanCoder