Какой правильный способ доступа к справочным данным в этом сценарии моделирования данных домена? - PullRequest
2 голосов
/ 01 июля 2010

Начальное предупреждение : Длинный пост и я, возможно, все равно получили неправильный шаблон:

Учитывая следующий класс, который является началом Агрегата клиентов:

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;}
}

Это хорошо, когда у меня есть объект customer с CustomerTypeId.Однако, когда я хочу заполнить DropDownList в моем MVC View, я пытаюсь понять, как правильно получить список значений CustomerType из ICustomerTypeRepostory.

ICustomerTypeRepository очень прост:

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

По сути, я хочу, чтобы у меня была возможность правильно вызывать ICustomerTypeRepository из моего контроллера, однако я подумал, что было бы лучше отделить слой DAL (хранилище) от контроллера.Теперь я просто усложняю вещи?

Вот как сейчас работает мой контроллер:

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():

public class CustomerType : ValueObject
{
   // ... Previous Code

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

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

Итак, каким образом я должен выставлять CustomerType объекты через ICustomerTypeRepository на CustomerController?

Ответы [ 2 ]

2 голосов
/ 09 июля 2010

Я думаю, что здесь есть несколько вещей, которые следует учитывать.

Прежде всего, если вы действительно заинтересованы в моделировании своего домена, вы захотите во что бы то ни стало попытаться сохранить доменные объекты свободнымисквозные проблемы, такие как проверка, контейнеры IoC и постоянство, несмотря на шаблон Active Record.

Это означает, что Customer, вероятно, не должно иметь никаких ссылок на репозиторий, даже если вы используетеинтерфейсы и сервисный локатор.Он должен быть спроектирован так, чтобы отражать атрибуты - или то, что составляет - «клиента» с точки зрения вашего целевого клиента / пользователя.

За исключением моделирования домена, меня немного беспокоит использованиевашего IoC сервисного локатора в инициализаторе переменной.Вы упускаете любую возможность ловить исключения и исключения, создаваемые конструкторами, как известно, их трудно отлаживать (эти инициализаторы запускаются перед любым кодом в вашем первом нестатическом конструкторе).

Использование статического шлюза / локатора службы вместоВнедрение зависимостей также делает класс практически непроверенным (с использованием методологий автоматического модульного тестирования, то есть - вы можете выполнять интеграцию и ручное тестирование, но неудачные тесты вряд ли укажут вам на сломанные биты - в отличие от модульного теста,где вы точно знаете, что именно вы тестируете и, следовательно, что не работает).

Вместо того, чтобы объект Customer заполнял себя данными, вызывая _customerRepository.Load(this) в конструкторе, приложение будет чаще использоватьхранилище для получения сущности, поэтому оно возвращается из хранилища, полностью заполненного, включая свойство CustomerType.В этом случае кажется, что это может произойти в CustomerController.

. Вы указываете, что хотели бы иметь отдельный DAL от слоя, в котором находится CustomerController, и у вас фактически это есть -- здесь вступает в действие интерфейс репозитория. Вы внедряете некоторую реализацию этого интерфейса (или в этом случае получаете реализацию из реализации IoC), но фактическая реализация этого репозитория может существовать вотдельный слой (это может быть даже другая сборка).Это шаблон, известный как отдельный интерфейс.

Лично я бы реорганизовал CustomerController, чтобы он выглядел так:

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 и любой другой класс сущностей домена.

0 голосов
/ 06 июля 2010

Как насчет изменения модели домена вашего клиента, чтобы включить свойство для 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
      }
   }
}
...