0

I've been struggling with this issue for a while. Let's say you have a business application that has a rich domain and in one of the front-end views you show a list of open Orders. In this view you show things like that orderDate, customerName, totalAmount,... but the client also wants to see how many items are in the order (basically the count of OrderItems entity). What is the best way to handle this?

Assumptions

  • The Order class has a List<OrderItem> which is fetched lazily
  • Each ResponseDTO object only contains its core properties and any properties from @ManyToOne associations (so Customer would be included when fetching an Order

Solution 1

You can do a rest call for the Order resource by calling /api/orders, you'll get a response with the core properties and the customer data. For each order you'll have to do a new fetch to /api/orders/<id>/items. This is basically an N+1 problem with many HTTP calls.

Solution 2

I change my initial assumption and eagerly fetch collections and immediately include the OrderItems in the ResponseDTO. The question then becomes, am I going to eagerly fetch each collection of each entity? This seems like a serious performance issue. In this solution the front end would only need to make 1 call.

Solution 3

Initial assumptions are in play, so I lazily fetch collections but I move the N+1 problem from the front-end to the back-end (so no extra HTTP calls), not really a solution but at least the expensive HTTP calls are weeded out.

Solution 4

In my rich domain model I add an attribute to the Order entity called numberOfItems. Whenever the method addOrderItem(OrderItem item) is invoked on an Order object, I increment the numberOfItems attribute. It is stored in the database as well. This way I can have all my initial assumptions and use the ResponseDTO with only core properties and I only make 1 HTTP call. The issue I have with this solution is that many people say that you shouldn't store aggregate data like that in the database.

I realize there's no perfect solution and it always depends, but for the life of me I can't seem to find good discussions about this issue. When you google an issue like this you often find information about HATEOAS but that would fit in my Solution 1, which I don't think is really a solution.

If anyone can give an alternative solution or improve on any of the solutions I gave, it would be greatly appreciated.

5
  • 2
    I think you should take REST out of the equation - it does not seem to be an essential part of the problem. You might want to use CQRS Read Models or custom DTOs instead of full fledged Entities for presentation. Commented Feb 16, 2018 at 11:11
  • @guillaume31 fair enough, REST is maybe not essential to this issue but I am using custom DTOS (the ResponseDTO) instead of full fledged entities. I've changed "REST" in the title to "web service" at least to differentiate between "true REST" and what is commonly called REST
    – Mekswoll
    Commented Feb 16, 2018 at 11:25
  • I'm not talking about the "response" data structure manipulated at the REST level, but about the data structure that gets mapped from the database. You can have a parallel Read circuit that doesn't use Entities at any point, which enables you to compose objects freely with as many calculations/aggregated fields as you need. Commented Feb 16, 2018 at 12:57
  • In your example, that would mean NumberOfItems goes to a new read-side OrderReadModel class but not to the Order entity. Commented Feb 16, 2018 at 13:03
  • 1
    @guillaume31, ok I see what you mean, I think that is probably a solution. It's sort of like creating a database view and querying that instead of the actual table
    – Mekswoll
    Commented Feb 16, 2018 at 13:34

2 Answers 2

2

I would agree with @guilaume31 and recommend to use a custom DTO / CQRS Read Model.

With a specified database query you could get the Orders and the number of OrderItems in only one query. Put that result in a specialised DTO and you're done.

Do not use Entities for this query!

0

Aside from the obvious solution of simply separating your command model from your read model (CQRS) to allow for divergence in terms of structure and fields (which I assume is out of the question), I'd propose either adopting Solution 2 or 4 above.

Although you say 2 is a serious performance issue, is it really? How many OrderItems are typically included in an Order? If the number isn't prohibitively large or each OrderItem isn't particularly complex, I wouldn't expect too much impact, in terms of performance, here. Furthermore, it's pretty common in this domain for Order to be an Aggregate Root including OrderItems so that it can enforce all sorts of possible invariants (like maximum price etc.). If that were to ever be the case, you would need to go this route anyway. Additionally, I can also reasonably imagine other instances where a user would like to see the list of OrderItems in an Order (that seems pretty fundamental does it not?).

If performance is truly an issue and it is unlikely you will need a list of OrderItems for some other feature, Solution 4 is your best bet. There is no reason to store numberOfItems as a field in the database though, and doing so violates the fundamental principals of the Entity Relational Model (there would be more than one way to find that information). The correct approach is to simply modify the query you use for Order hydration to calculate the numberOfItems and provide the count in your Result Set. The numberOfItems property needn't be used during persistence.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.