初始警告:很长的帖子,无论如何我可能完全错了:
给出以下类,它是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();
}
}
那么,我应该通过CustomerType
向ICustomerTypeRepository
公开CustomerController
个对象的方式是什么?
答案 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
}
}
}