如何在 DDD 中执行此操作而不从域实体引用存储库?

发布于 2024-12-11 19:15:34 字数 1034 浏览 0 评论 0原文

我正在努力寻找合适的设计来避免从实体引用存储库...假设我有经典的 CustomerOrder 类,如下所示:

public class Customer {
    ...
    public IEnumerable<Order> Orders { get; set; }
}

public class Order {
    ...
    public Customer Customer { get; set; }
    public IEnumerable<OrderItem> OrderItems { get; set; }

    public void Submit() {
       ...
    }
}

public class OrderItem {
    public Product Product { get; set; }
    public decimal SellingPrice { get; set; }
}

现在,假设产品的售价由于某种原因取决于以下事实:该产品也在上一个订单中购买(或未购买)、当前订单和上一个订单上的商品数量等。我可以这样做:

public void Submit() {
    Order lastOrder = this.Customer.Orders.LastOrDefault();
    CalculatePrice(lastOrder);

但这会加载整个订单列表的订单,而我只需要最后一个!

我想做的事情更像是这样的:

public void Submit() {
    Order lastOrder = _orderRepository.GetLastOrderFor(Customer);
    CalculatePrice(lastOrder);

但我知道在域中引用 OrderRepository 是不好的 DDD。那么,我该怎么办?我是否必须将 Submit() 放在域以外的其他地方?如果是这样,你建议去哪里?

I'm struggling hard to find a proper design to avoid referencing a Repository from an Entity... Let's say I've got the classic Customer and Order classes like so:

public class Customer {
    ...
    public IEnumerable<Order> Orders { get; set; }
}

public class Order {
    ...
    public Customer Customer { get; set; }
    public IEnumerable<OrderItem> OrderItems { get; set; }

    public void Submit() {
       ...
    }
}

public class OrderItem {
    public Product Product { get; set; }
    public decimal SellingPrice { get; set; }
}

Now, let's say that the Product's selling price depends for some reason on the fact that the Product was also purchased (or not) on the previous Order, the number of items on the current order and previous order, etc. I could do this:

public void Submit() {
    Order lastOrder = this.Customer.Orders.LastOrDefault();
    CalculatePrice(lastOrder);

but that would load the whole order list of Orders when I only really need the last one!

What I'd like to do is something more like this:

public void Submit() {
    Order lastOrder = _orderRepository.GetLastOrderFor(Customer);
    CalculatePrice(lastOrder);

But I understand referencing the OrderRepository in the Domain is bad DDD. So, what do I do? Do I have to put the Submit() elsewhere than in the Domain? If so, where do you suggest?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

命比纸薄 2024-12-18 19:15:34

您有两种选择:

创建域服务并从中添加对存储库的依赖项:

public class MyPricingStrategy : IPricingStrategy
{
  public MyPricingStrategy(IOrderRepository repository)
  { ... }
}

这样您将创建域服务引用存储库,这不是一个坏主意。

另一种选择是使定价策略成为一个域对象,应用程序层向其传递来自存储库的所需数据:

public class LastOrderPricingStrategy
{
  public LastOrderPricingStrategy(Order lastOrder)
  { ... }
}

在应用程序层中

var lastOrder = orderRepository.GetLastOrder(currentCustomer);
var pricingStrategy = new LastOrderPricingStrategy(lastOrder);

You have two varieties:

Create a domain service and add a dependency to the repository from it:

public class MyPricingStrategy : IPricingStrategy
{
  public MyPricingStrategy(IOrderRepository repository)
  { ... }
}

this way you will make domain service reference repository which is not very bad idea.

Another option is to make the pricing strategy a domain object with application layer passing it required data from repository:

public class LastOrderPricingStrategy
{
  public LastOrderPricingStrategy(Order lastOrder)
  { ... }
}

in application layer

var lastOrder = orderRepository.GetLastOrder(currentCustomer);
var pricingStrategy = new LastOrderPricingStrategy(lastOrder);
雄赳赳气昂昂 2024-12-18 19:15:34

Customer 对象可以有一个 LastOrder 属性:

public class Customer {
    ...
    public IEnumerable<Order> Orders { get; set; }
    public Order LastOrder { get; set; }
}

因此下订单的部分逻辑会设置此字段,并且该字段将与 Customer 一起保存。然后,当您加载客户时,您将很快知道最后的订购方式是什么,并据此做出相应的决策。

另一种方式,如果您使用像 NHibernate 这样的 ORM,您可以创建一个多重查询来急切地加载仅包含最后一个订单的 Orders 集合。然后你可以回去使用这个:

public void Submit() {
    Order lastOrder = this.Customer.Orders.LastOrDefault();
    CalculatePrice(lastOrder);

它不需要加载任何东西,因为你需要的顺序就在那里。只急切地加载集合中我需要的对象是我经常使用的一种模式。

The Customer object could have a LastOrder property:

public class Customer {
    ...
    public IEnumerable<Order> Orders { get; set; }
    public Order LastOrder { get; set; }
}

So part of the logic of making an order sets this field, and this will be saved with the Customer. Then when you load the customer, you will quickly know what the last order way, and make your decisions based on that accordingly.

Another way, if you are using an ORM like NHibernate, you could create a multi query to eagerly load the Orders collection with only the last order. then you could go back to using this:

public void Submit() {
    Order lastOrder = this.Customer.Orders.LastOrDefault();
    CalculatePrice(lastOrder);

and it would not need to load anything because the order you need will be in there. Eagerly loading only the objects I'm going to need in a collection is a pattern I use quite a lot.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文