Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it okay to bypass the repository pattern for complex queries?

This is my understanding about DDD at the moment:

  • The strict repository pattern should only implement get(), delete() and create(), and maybe variants of get() where one can search or to retrieve an entire collection
  • It is common for each aggregate root to have one repository

(from research, I know those are not universally accept norms)

The question here is how to implement complex queries which involves many aggregate roots. For example, we have two aggregate roots - product and user. If I am doing a page which list what products a user have bought, then I have a query which stretch across both the user aggregate and the product aggregate.

How should this query be implemented?

  1. What I am doing now is actually to have a repository for this query and queries with related functionality (some will disagree and say the repository is not a query layer).

  2. Use only the repository for product and user, grab all records and do everything in memory (this sounds wrong)

  3. Have the query (LINQ or SQL) to be inside the service, not using the repository associated with the aggregates at all.

Are there some other ways?

like image 483
Extrakun Avatar asked Sep 03 '11 07:09

Extrakun


2 Answers

The strict repository pattern should only implement get(), delete() and create(), and maybe variants of get() where one can search or to retrieve an entire collection

Repository interface is part of your domain and should be based on Ubiquitous Language as much as possible. All Repositories are different just like all your Aggregates are different. Strict, generic repositories are CRUD overgeneralization and may reduce code expressiveness. 'Create' method also does not belong to Repository because beginning of object life cycle is usually handled by Factory or Object itself. 'Add' seems like a better name when you want to persist existing object because Repository has a collection semantics.

The question here is how to implement complex queries which involves many aggregate roots. For example, we have two aggregate roots - product and user. If I am doing a page which list what products a user have bought, then I have a query which stretch across both the user aggregate and the product aggregate.

In this case you just have to listen to the business requirements, I emphasized the part that I think is most important. Based on that it looks like you need:

Products products = /* get Products repository implementation */;
IList<Product> res = products.BoughtByUser(User user);

The idea of organizing code like that is to match business requirements and ubiquitous language as much as possible. The naming of the repository interfaces is also important, I prefer to have Products or AllProducts instead of ProductsRepository. Phil Calçado has a very good article on this subject, highly recommended.

How should this query be implemented?

There is nothing special about this query, it can be implemented just like all other queries in Products repository. The querying itself is hidden from Domain because Repository implementation belongs to Data Access layer. Data Access can implement any query because it has intimate knowledge of all the Aggregates and their relationships. At this point it would just be a Hibernate or SQL question.

like image 65
Dmitry Avatar answered Nov 09 '22 18:11

Dmitry


First of all, queries are rarely done against Aggregate Roots. They are done against data and return just data. Repositories are very handy abstractions of persistence for using in application layer (commands and such) code. We need them there because we want to be able to test this layer without need for a database. That's why the smaller the repository the better -- it's easier to mock it.

I tend to use specialized Finder objects that allow my UI to query the data store. I even place my Finders in the UI layer. The thing is, they tend to change every time UI changes so it's better to put them together. Another good reason why you don't want to put query methods on the repository is, repository is part of your domain, your ubiquitous language. You don't want to pollute them with UI concepts that tend to be short living and rapidly changing.

I've written a blog post explaining this concept some time ago. You can find it here.

like image 38
Szymon Pobiega Avatar answered Nov 09 '22 19:11

Szymon Pobiega