在这个域数据建模场景中访问参考数据的正确方法是什么?
初始警告:很长的帖子,我可能已经得到了完全错误的模式:
给定以下类,它是客户聚合的开始:
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(存储库)分开)来自控制器的层。现在,我是否把事情过于复杂化了?
这就是我的控制器目前的情况:
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();
}
}
所以,这就是我应该通过 ICustomerTypeRepository
公开 CustomerType
对象的方式> 到 CustomerController
?
Initial Warning: Long post and I might have got the pattern totally wrong anyway:
Given the following class which is the start of the 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);
}
}
}
And CustomerType is represented by a value object:
public class CustomerType : ValueObject
{
public virtual int CustomerTypeId {get;set;}
public virtual string Description {get;set;}
}
This is all well and good for when I have a customer object with a CustomerTypeId. However, when I want to populate a DropDownList within my MVC View, I'm struggling with the concept of how to correctly get the CustomerType value list from the ICustomerTypeRepostory.
The ICustomerTypeRepository
is very simple:
public interface ICustomerTypeRepository
{
public CustomerType Get(int customerTypeId);
public IEnumerable<CustomerType> GetList();
}
Basically, what I want is to be able to call ICustomerTypeRepository
correctly from my Controller, however I thought it would be best to separate the DAL (repository) layer from the controller. Now, am I just overcomplicating things?
This is how my controller currently stands:
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 );
}
}
This seems wrong to me as I've got repositories in the Controller and in Customer. It just appears logical to me that there should be a segragated access layer for CustomerType. I.e. CustomerType.GetList()
:
public class CustomerType : ValueObject
{
// ... Previous Code
private static ICustomerTypeRepository _customerTypeRepository = IoC.Resolve(..);
public static IEnumerable<CustomerType> GetList()
{
_customerTypeRepository.GetList();
}
}
So, which is the way I should be exposing the CustomerType
objects through the ICustomerTypeRepository
to the CustomerController
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为这里有一些事情需要考虑。
首先,如果您确实对域建模感兴趣,那么您将需要不惜一切代价尝试使域实体本身免于横切问题,例如验证、IoC 容器和持久性,尽管有 Active Record 模式。
这意味着
Customer
可能不应该有任何对存储库的引用,即使您正在使用接口和服务定位器。它的设计应该从目标客户/用户的角度反映“客户”的属性或构成因素。除了域建模之外,我有点担心在变量初始值设定项中使用 IoC 服务定位器。您将失去任何捕获异常的机会,并且构造函数抛出的异常非常难以调试(这些初始化程序在第一个非静态构造函数中的任何代码之前运行)。
使用静态网关/服务定位器代替注入依赖项也会使该类几乎无法测试(使用自动化单元测试方法,也就是说,您可以进行集成和手动测试,但测试失败不太可能将您指向损坏的地方)位很容易——与单元测试相反,在单元测试中你确切地知道你正在测试什么,因此知道什么被破坏了)。
应用程序通常会使用存储库来获取实体,而不是通过在构造函数中调用
_customerRepository.Load(this)
来让Customer
对象向自身填充数据,因此它从完全填充的存储库中返回,包括CustomerType
属性。在这种情况下,这似乎可能发生在CustomerController
中。您表明您希望拥有一个与
CustomerController
所在的层分开的 DAL,并且您实际上已经拥有了它——这就是使用存储库接口的用武之地。您注入一些 该接口的实现(或者在本例中,从 IoC 实现获取实现),但该存储库的实际实现可以存在于单独的层中(甚至可以是另一个程序集)。这是一种称为分离接口的模式。就我个人而言,我会将 CustomerController 重构为如下所示:
…并且我将从
Customer
和任何其他域实体类中获取对存储库的所有引用。I think there are a few things to consider here.
First of all, if you are really interested in modeling your domain, you'll want to try at all costs to keep domain entities themselves free of cross-cutting concerns, like validation, IoC containers, and persistence, the Active Record pattern notwithstanding.
What this means is that
Customer
should probably not have any reference to a repository, even if you're using interfaces and a service locator. It should be designed to reflect the attributes of -- or what constitutes -- a "customer" from the perspective of your target client/user.Domain-modeling aside, I'm a little concerned by the use of your
IoC
service locator in a variable initializer. You forfeit any opportunity to catch exceptions and exceptions thrown by constructors are notoriously hard to debug (these initializers run before any code in your first non-static constructor).The use of the static gateway/service locator in lieu of injecting dependencies also renders the class virtually untestable (using automated unit testing methodologies, that is -- you can do integration and manual testing, but test failures are unlikely to point you to the broken bits readily -- as opposed to a unit test, where you know exactly what one thing you are testing and therefore what is broken).
Instead of having the
Customer
object populate itself with data by calling_customerRepository.Load(this)
in the constructor, an application will more typically use the repository to get the entity, so it comes back from the repository wholly populated, including theCustomerType
property. In this case, it appears that this might occur in theCustomerController
.You indicate that you would want to have a separate DAL from the layer in which the
CustomerController
resides, and you effectively have that -- this is where using a repository interface comes in. You inject some implementation of that interface (or in this case, get an implementation from the IoC implementation), but the actual implementation of that repository can exist in a separate layer (it can be another assembly even). This is a pattern known as Separated Interface.Personally, I would refactor the CustomerController to look like this:
…and I'd take any and all references to repositories out of
Customer
and any other domain entity class.如何更改您的客户域模型以包含 CustomerTypes 的属性?这也将不再需要每次调用 CustomerType 时都访问存储库。
How about changing your customer domain model to include a property for CustomerTypes? This would also stop the need to hit the repository each time CustomerType is called.