nab*_*rid 21 c# orm domain-driven-design repository-pattern
我在不使用ORM的.NET C#应用程序中使用存储库模式.但是,我遇到的问题是如何填充实体的一对多列表属性.例如,如果客户有一个订单列表,即如果Customer类有一个名为Orders的List属性,而我的存储库有一个名为GetCustomerById的方法,那么?
这也引发了诸如变更跟踪,删除等功能的问题?所以我认为最终结果是我可以在没有ORM的情况下进行DDD吗?
但是现在我只对我的域实体中的延迟加载List属性感兴趣?任何的想法?
纳比勒
我假设对于没有在域驱动设计中使用ORM的人来说这是一个非常常见的问题?任何的想法?
Dav*_*ers 12
没有ORM我可以做DDD吗?
是的,但ORM简化了事情.
说实话,我认为你的问题与你是否需要ORM无关 - 这是你对数据的过多考虑,而不是DDD成功的关键行为.就数据模型而言,大多数实体将以某种形式与大多数其他实体建立关联,从这个角度来看,您可以遍历整个模型.这就是您的客户和订单的样子,也许您认为需要延迟加载的原因.但是你需要使用聚合来将这些关系分解为行为组.
例如,为什么您将客户聚合建模为具有订单列表?如果答案是"因为客户可以订购",那么我不确定您是否处于DDD的心态.
有什么行为要求客户拥有订单清单?当您更多地考虑域的行为(即在什么点需要什么数据)时,您可以根据用例对事物进行建模,事情变得更加清晰和简单,因为您只需更改跟踪一小组对象在总边界.
我怀疑Customer应该是一个没有订单列表的单独聚合,Order应该是一个包含订单行列表的聚合.如果您需要对客户的每个订单执行操作,请使用orderRepository.GetOrdersForCustomer(customerID); 进行更改然后使用orderRespository.Save(order);
关于没有ORM的更改跟踪,您可以通过多种方式执行此操作,例如,订单聚合可能会引发订单存储库正在侦听已删除订单行的事件.然后可以在完成工作单元时删除这些内容.或者稍微不那么优雅的方法是维护已删除的列表,即您的存储库显然可以读取的order.DeletedOrderLines.
总结一下:
编辑回应评论:
我不认为我会为订单行实现延迟加载.您可以在订单上执行哪些操作而无需订单行?我怀疑的并不多.
但是,当它看起来没有意义时,我不是一个被限制在DDD的"规则"的人,所以...如果在不太可能的情况下,对订单对象执行了许多操作,那么"T需要的顺序线填充和经常有大量的相关联的订单订单行(都必须是真实的我认为这是一个问题),那么我应该这样做:
在订单对象中有此私有字段:
private Func<Guid, IList<OrderLine>> _lazilyGetOrderLines;
Run Code Online (Sandbox Code Playgroud)
订单存储库将在创建时将其传递给订单:
Order order = new Order(this.GetOrderLines);
Run Code Online (Sandbox Code Playgroud)
这是OrderRepository上的私有方法:
private IList<OrderLine> GetOrderLines(Guid orderId)
{
//DAL Code here
}
Run Code Online (Sandbox Code Playgroud)
然后在订单行属性可能看起来像:
public IEnumberable<OrderLine> OrderLines
{
get
{
if (_orderLines == null)
_orderLines = _lazilyGetOrderLines(this.OrderId);
return _orderLines;
}
}
Run Code Online (Sandbox Code Playgroud)
编辑2
我发现这篇博文与我的解决方案类似,但更优雅:
http://thinkbeforecoding.com/post/2009/02/07/Lazy-load-and-persistence-ignorance
1) 我应该在 GetCustomerById 方法中加载订单列表吗?
将订单映射代码与客户映射代码分开可能是个好主意。如果您手动编写数据访问代码,从GetCustomerById方法调用该映射模块是您的最佳选择。
2)如果Order本身有另一个列表属性等等怎么办?
将所有这些放在一起的逻辑必须存在于某个地方;相关的聚合存储库是一个很好的地方。
3)如果我想延迟加载怎么办?我应该在哪里放置代码来加载客户中的 Orders 属性?在 Orders 属性内部 get{} 访问器?但随后我必须将存储库注入域实体中?我认为这不是正确的解决方案。
我见过的最好的解决方案是让您的存储库返回子类域实体(使用诸如Castle DynamicProxy之类的东西) - 这可以让您在域模型中保持持久性无知。