在此域数据建模方案中访问参考数据的正确方法是什么?

时间:2010-07-01 16:22:49

标签: c# asp.net-mvc-2 repository-design domain-data-modelling

初始警告:很长的帖子,无论如何我可能完全错了:

给出以下类,它是Customer Aggregate的开头:

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

基本上,我想要的是能够从我的Controller正确调用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 );
    }
}

这对我来说似乎不对,因为我在Controller和Customer中都有存储库。对我而言,对于CustomerType应该有一个分层的访问层,这似乎是合乎逻辑的。即CustomerType.GetList()

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

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

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

那么,我应该通过CustomerTypeICustomerTypeRepository公开CustomerController个对象的方式是什么?

2 个答案:

答案 0 :(得分:2)

我认为这里有一些事情需要考虑。

首先,如果您真的对建模域名感兴趣,那么您将不惜一切代价来保持域实体本身不受横切关注,例如验证,IoC容器和持久性,Active Record尽管如此。

这意味着Customer可能不应该对存储库有任何引用,即使您使用的是接口和服务定位器。它应该被设计为从目标客户/用户的角度反映“客户”的属性或构成什么。

除了域建模之外,我有点担心在变量初始化程序中使用IoC服务定位器。你没有机会捕获异常,构造函数抛出的异常很难调试(这些初始化器在你的第一个非静态构造函数中的任何代码之前运行)。

使用静态网关/服务定位器代替注入依赖项也会使类几乎不可测试(使用自动单元测试方法,即 - 您可以进行集成和手动测试,但测试失败不太可能指向您容易破碎 - 与单元测试相反,你可以确切知道你正在测试的是什么,因此破坏了什么。

而不是让Customer对象通过在构造函数中调用_customerRepository.Load(this)来填充数据,应用程序通常会使用存储库来获取实体,因此它从完全填充的存储库返回,包括CustomerType属性。在这种情况下,似乎可能会出现在CustomerController

您表示您希望从CustomerController所在的层中获得单独的DAL,并且您实际上已经拥有了这个 - 这是使用存储库接口的地方。您注入了一些该接口的实现(或者在这种情况下,从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和任何其他域实体类中获取对存储库的任何和所有引用。

答案 1 :(得分: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
      }
   }
}