33

I am trying to understand the "Query object design pattern". I am not able to find good and simple examples for it. Could someone help me to understand what this design pattern is for and in what problem we can implement this?

matino
  • 17,199
  • 8
  • 49
  • 58

3 Answers3

41

The Query design pattern is usually used in combination with the Repository design pattern.

Let us go with an example and then I will give a nice article to read. Let's say that we have a database where we store information about our customers and their orders, etc.

Then we create an initial repository like this:

class CustomerRepository() {
    Customer GetById(int id) { // implementation }
    void DeleteCustomer(int id) { // impl }
    Customer GetCustomerWithOrder(int orderId);
    Customer[] GetCustomersWithOrdersMoreThan(int numberOfOrders);
}

As you can see for every query we created a method in the repository which is very fine and well for limited number of queries but when we have a lot of them and they start getting complicated with a lot of combinations (e.g. get me customers with purchases that exceed 1000 and live in New York and their credit limit is less than 3000) then we will end up with a long list of methods and even worse, leaking some business logic in the shape of queries inside the repositories which we don't want to happen.

So to refactor that we change the repository to something like this:

class CustomerRepository() {
    Customer[] Get(Query query) { // implementation }
    void DeleteCustomer(int id) { // impl }
}

As you can see we are passing a Query Object which represents our query in the form of an object and the repository has one and only repository to execute that query and give us the results back.

Now how implement that query object and how to build it will require a lot of code so at this point i will direct you over to this nice article. It is in C# but you will find it very helpful, also you can look at the Criteria API (Java) which is used by NHibernate to see a different but similar implementation.

aquaraga
  • 4,138
  • 23
  • 29
Ibrahim Najjar
  • 19,178
  • 4
  • 69
  • 95
  • 1
    ok, I understand the exact use of the query object design pattern now. Nice example and nice explanaiton.Thank you so much. And now I have another question related to this. The criteria API provides the query object design pattern and simply we can use it. But little bit confused about implementing this programatically. In the example you mentioned above, you are injecting the Query object. But how does it look like if I want to implement this in my app? –  Jul 29 '13 at 14:52
  • 1
    @santu What language are you using and have you checked the article in C# i told you about ? – Ibrahim Najjar Jul 29 '13 at 16:55
  • I am using Java. I checked C#. But I thought how to use this pattern for just the DAO calls which does the different individuyal CRUD operations. –  Aug 16 '13 at 13:32
  • 1
    @santu You won't need that for simple CRUD operations like add, update, delete and read. You only need this for complex queries. – Ibrahim Najjar Aug 16 '13 at 13:44
  • What if we need to pull the data off two different tables? how will a customer repository pulling data only from the Customer table be useful in a real world scenario? – user20358 Nov 07 '16 at 02:02
  • @user20358 You aren't restricted to accessing one table per repository. Actually it is preferable that you use a repository per aggregate root if you like which loads an entity and its child entities. – Ibrahim Najjar Nov 07 '16 at 15:26
8

The Query Object represented a query written in the language of the domain and was an implementation of the Query Object pattern. The Query Object pattern as described by Fowler is “an object that represents a database query.” Without some mechanism of querying, the Repository would be awash with myriad retrieval methods such as can be seen in this code snippet:

public interface ICustomerRepository     
{         
    IEnumerable<Customer> FindAll();
    IEnumerable<Customer> FindAllVIPCustomers();
    IEnumerable<Customer> FindByOrder(Guid ID);
    IEnumerable<Customer> FindAllCustomersThatHaveOutstandingOrders();
    …    
}

Instead, the Query Object enables any query to be constructed and then sent to the Repository to be satisfied. The major benefit of the Query Object pattern is that it completely abstracts away the underlying database querying language and thus keeps the infrastructure concerns of data persistence and retrieval out of the business layer. At some point, however, the raw querying language of the database needs to be created; this is achieved using a database-specific QueryTranslator that takes the Query Objects and converts them into the language of the database.

From Pro ASP.NET Design Patterns book.

Bulut Paradise
  • 161
  • 1
  • 7
0

Have a look at the query object pattern library I wrote for NHibernate: https://github.com/shaynevanasperen/NHibernate.Sessions.Operations

Shayne
  • 195
  • 1
  • 10