Search code examples
domain-driven-designddd-repositories

How to do this in DDD without referencing the Repository from the domain entity?


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?


Solution

  • 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);