2

초기 경고 : 긴 포스트와 나는 어쨌든 완전히 잘못된 패턴을 가지고 있습니다이 도메인 데이터 모델링 시나리오에서 참조 데이터에 액세스하는 올바른 방법은 무엇입니까?

고객 집계의 시작 다음 클래스 감안할를 :

public class Customer : KeyedObject 
{ 

    public Customer(int customerId) 
    { 
     _customerRepository.Load(this); 
    } 

    private ICustomerRepository _customerRepository = IoC.Resolve(..); 
    private ICustomerTypeRepository = _customerTypeRepository = IoC.Resolve(..); 

    public virtual string CustomerName {get;set;} 
    public virtual int CustomerTypeId [get;set;} 

    public virtual string CustomerType 
    { 
     get 
     { 
     return _customerTypeRepository.Get(CustomerTypeId); 
     } 
    } 

} 

그리고 CustomerType은로 표현된다 값 개체 :

public class CustomerType : ValueObject 
{ 
    public virtual int CustomerTypeId {get;set;} 
    public virtual string Description {get;set;} 
} 

CustomerTypeId를 사용하여 고객 개체를 만들 때 유용합니다. 그러나 MVC 뷰 내에서 DropDownList를 채울 때 ICustomerTypeRepostory에서 CustomerType 값 목록을 올바르게 가져 오는 방법에 대한 개념에 어려움을 겪고 있습니다.

ICustomerTypeRepository은 매우 간단합니다 : 기본적으로

public interface ICustomerTypeRepository 
{ 
    public CustomerType Get(int customerTypeId); 
    public IEnumerable<CustomerType> GetList(); 
} 

, 내가 원하는 것은 내 컨트롤러에서 제대로 ICustomerTypeRepository를 호출 할 수있다, 그러나 나는 그것을에서 DAL (저장소) 층을 분리하는 가장 좋은 것이라고 생각 컨트롤러. 지금, 나는 단지 것들을 overcomplicating? 나는 컨트롤러 및 고객의 저장소를 가지고로

public class CustomerController : ControllerBase 
{ 

    private ICustomerTypeRepository _customerTypeRepository = IoC.Resolve(..); 

    public ActionResult Index() 
    { 
     Customer customer = new Customer(customerId); 
     IEnumerable<CustomerType> customerTypeList = 
      _customerTypeRepository.GetList(); 

     CustomerFormModel model = new CustomerFormModel(customer); 
     model.AddCustomerTypes(customerTypeList); 
    } 
} 

이 나에게 잘못 보인다

이 내 컨트롤러가 현재의 약자 방법이다. CustomerType에 대해 단편화 된 액세스 레이어가 있어야한다는 것이 내게 논리적 인 것처럼 보입니다. 나는. CustomerType.GetList() :

내가 CustomerControllerICustomerTypeRepository을 통해 CustomerType 오브젝트를하는 방식에 노출되어야한다 그래서
public class CustomerType : ValueObject 
{ 
    // ... Previous Code 

    private static ICustomerTypeRepository _customerTypeRepository = IoC.Resolve(..); 

    public static IEnumerable<CustomerType> GetList() 
    { 
     _customerTypeRepository.GetList(); 
    } 
} 

?

+0

'고객'유형의 고정 목록이 있습니까? 아니면 추가되는 새로운 사용자 생성 고객 유형이 있습니까? – Jay

+0

@ 제이 - 사실, 이것은 단지 예일뿐입니다. 그러나 사용자가 생성 한 고객 유형이 추가되어 열거 형 등을 사용할 수 없습니다. – GenericTypeTea

답변

2

여기 몇 가지 고려해야 할 사항이 있습니다.

우선 도메인을 모델링하는 데 관심이 있다면 검증, IoC 컨테이너 및 지속성과 같은 교차 관심사가없는 도메인 엔티티 자체를 유지하기 위해 모든 비용을 들이고 싶을 것입니다. Active 기록 패턴에도 불구하고.

이것은 인터페이스 및 서비스 위치 지정자를 사용하는 경우에도 Customer에 저장소에 대한 참조가 없을 것임을 의미합니다. 대상 클라이언트/사용자의 관점에서 "고객"의 속성 또는 구성 요소를 반영하도록 설계되어야합니다.

도메인 모델링과는 별도로 변수 이니셜 라이저에 서비스 로케이터 IoC을 사용하면 조금 걱정됩니다. 예외를 잡을 수있는 기회를 놓치고 생성자가 던진 예외는 디버그하기가 매우 어렵습니다 (이 초기화 프로그램은 첫 번째 비 정적 생성자의 코드보다 먼저 실행됩니다).

의존성 주입 대신 정적 게이트웨이/서비스 로케이터를 사용하면 자동화 된 유닛 테스트 방법론을 사용하여 클래스를 사실상 테스트 할 수 없게됩니다. 즉, 통합 및 수동 테스트를 수행 할 수 있지만 테스트 실패는 발생하지 않습니다 당신은 부서진 작은 조각들에 쉽게 접근 할 수 있습니다 - 단위 테스트와는 반대로, 당신이 무엇을 테스트하고 있는지, 그리고 무엇이 고장 났는지 정확하게 알 것입니다.) 대신 Customer 객체가 생성자에서 _customerRepository.Load(this)를 호출하여 데이터 자체를 채우는 데

이 응용 프로그램은 더 일반적으로 개체를 얻을 수있는 저장소를 사용합니다, 그래서 다시 CustomerType 재산을 포함하여 완전히 채워 저장소에서 제공됩니다. 이 경우 CustomerController에서 발생할 수 있습니다.

당신은 당신이 CustomerController 상주하고 효과적으로 그이있는 레이어는 별도의 DAL을 할 것이라고 표시 - 저장소 인터페이스로 제공하여 곳이다 당신은 그 인터페이스의 일부 구현 주입. (또는이 경우에는 IoC 구현에서 구현을 가져옵니다). 그러나 해당 저장소의 실제 구현은 별도의 계층에 존재할 수 있습니다 (다른 어셈블리 일 수도 있음). 이것은 Separated Interface로 알려진 패턴입니다.

public class CustomerController : ControllerBase 
{ 
    private ICustomerTypeRepository _customerTypeRepository; 
    private ICustomerRepository _customerRepository; 

    public CustomerController(ICustomerRepository customerRepository, 
     ICustomerTypeRepository customerTypeRepository) 
    { 
     _customerRepository = customerRepository; 
     _customerTypeRepository = customerTypeRepository; 
    } 

    public ActionResult Index() 
    { 
     Customer customer 
      = _customerRepository.GetCustomerWithId(customerId); 
      // from where does customerId come? 

     IEnumerable<CustomerType> customerTypeList 
      = _customerTypeRepository.GetTypes(); 

     . . . 

    } 
} 

을 ... 그리고 나는 Customer 중 저장소에 대한 모든 참조와 다른 도메인 엔티티 클래스를 취할 것 :

개인적으로, 나는 다음과 같이 할 수 CustomerController 리팩토링 것입니다.

0

CustomerTypes에 대한 속성을 포함하도록 고객 도메인 모델을 변경하는 방법은 어떻습니까? 이렇게하면 CustomerType이 호출 될 때마다 저장소에 도달 할 필요가 없어집니다.

public class Customer : KeyedObject 
{ 

    public Customer(int customerId) 
    { 
     _customerRepository.Load(this); 

     ICustomerTypeRepository _customerTypeRepository = IoC.Resolve(..); 
     _customerTypes = _customerTypeRepository.GetList(); 
    } 

    private ICustomerRepository _customerRepository = IoC.Resolve(..); 

    public virtual string CustomerName {get;set;} 
    public virtual int CustomerTypeId {get;set;} 

    public virtual string CustomerType 
    { 
     get 
     { 
     return _customerTypes.Find(CustomerTypeId); 
     } 
    } 

    private IEnumerable<CustomerType> _customerTypes; 
    public virtual IEnumerable<CustomerType> CustomerTypes 
    { 
     get 
     { 
      return _customerTypes 
     } 
    } 
} 
+0

그게 그거야. CustomerTypes 목록에 액세스 (예 : 양식의 드롭 다운 만 채우기)하기 위해 고객을로드해야하는 것은 잘못되었습니다. – GenericTypeTea

+0

귀하의 질문에 CustomerController.Index는 CustomerFormModel에 고객 유형을로드하므로 동일한 모델에서 고객 및 고객 유형 목록이 필요하다고 가정했습니다. 그렇지 않은가요? 어쩌면 내가 두껍거나 질문에 약간의 수정이 필요할지 모른다. –

+0

나는 그것을 한 방향으로 이해한다고 생각합니다. 하지만 CustomerTypes 편집을 추가하려는 관리자 양식을 가지고 있다면 어떨까요? 그 시점에서 고객 개념이 없기 때문에 Customer 객체를로드하고 싶지는 않습니다. – GenericTypeTea