在此域数据建模方案中访问参考数据的正确方法是什么?
-
01-10-2019 - |
题
最初的警告: :长篇文章,我可能还是完全错误的:
给定以下课程,这是客户汇总的开始:
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);
}
}
}
自定义类型由一个值对象表示:
public class CustomerType : ValueObject
{
public virtual int CustomerTypeId {get;set;}
public virtual string Description {get;set;}
}
这一切都很好,非常适合当我拥有带有自定型的客户对象时。但是,当我想在我的MVC视图中填充一个下拉列表时,我正在为如何正确获取从iCustomertypeperpostory获取自定义类型值列表的概念。
这 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 );
}
}
我似乎是错误的,因为我在控制器和客户中都有存储库。对我来说似乎合乎逻辑的是,自定义类型应该有一个分离的访问层。 IE CustomerType.GetList()
:
public class CustomerType : ValueObject
{
// ... Previous Code
private static ICustomerTypeRepository _customerTypeRepository = IoC.Resolve(..);
public static IEnumerable<CustomerType> GetList()
{
_customerTypeRepository.GetList();
}
}
所以,这就是我的方式 应该 公开 CustomerType
通过 ICustomerTypeRepository
到 CustomerController
?
解决方案
我认为这里有几件事要考虑。
首先,如果您真的有兴趣建模域名,那么您仍需要尝试使域实体本身不受跨切割问题的范围,例如验证,IOC容器和持久性,即使有主动的记录模式。
这意味着 Customer
即使您使用接口和服务定位器,也可能没有任何对存储库的引用。它应该设计为反映目标客户端/用户的角度来反映“客户”的属性或构成的属性。
除了域模型,我对您的使用有点关注 IoC
可变初始化器中的服务定位器。众所周知,您没有机会捕获构造函数的异常和例外的任何机会很难进行调试(这些初始化器在第一个非静态构造函数中的任何代码之前运行)。
使用静态网关/服务定位器代替注入依赖项,也可以使该类几乎无法测试(使用自动化的单元测试方法,也就是说 - 您可以进行集成和手动测试,但是测试失败不太可能指向损坏的测试失败比特很容易 - 与单位测试相反,您确切地知道要测试的一件事,因此什么是损坏的)。
而不是拥有 Customer
对象通过调用数据填充自身 _customerRepository.Load(this)
在构造函数中,应用程序通常会更通常使用存储库来获取实体,因此它从存储库完全填充,包括 CustomerType
财产。在这种情况下,看来这可能发生在 CustomerController
.
您指出您希望与 CustomerController
居住,您有效地拥有 - 这是使用存储库接口进来的地方。您注入 一些 该接口的实现(或在这种情况下,从IOC实施中获取实现),但是该存储库的实际实现可以在单独的层中存在(甚至可以是另一个程序集)。这是一种称为分离界面的模式。
就我个人而言,我会重构定制器以这样的样子:
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
以及任何其他域实体类。
其他提示
如何更改客户域模型以包括自定义型的属性?这也将停止每次调用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
}
}
}