home
post
repository and query object

Repository and Query Object

Feb 17, 2024
5 min
1 chart

The Repository is a design pattern, which helps to load data from the database providing abstract API, concealing the storage implementation details.

The Query Object pattern enables the creation of declarative queries adaptable to different database (or any storage) implementations.

Combination of these two patterns creates a robust API for loading domain objects from external source, obscuring the implementation details while providing declarative querying interface.

Terms and Concepts

  • Abstract API - a programming interface, which is decoupled or loosely coupled to the implementation. Defining Abstract API over the implementation allows to conceal the implementation details.
  • Declarative query - query which is created by saying what to find, instead of how to find.
  • Domain objects - refers to the object, which is a part of a domain, not a random object in the system Domain objects are always persisted to a database. Repository pattern the abstracts database from the runtime domain objects.

This is the quote from his book:

Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.

Martin fowler

Chart Description

Chart below is a UML class diagram. It depicts how the Repository and Query Objects patterns can be used together. I'm omitting the ORM in this diagram on purpose, not to over-complicate it.

  • Repository is an abstract interface with one method that loads items by criteria(Query Object) and returns collection like domain objects. This is the main point of mapping, loading and caching domain objects.
  • ItemRepository implements Repository interface. It uses ItemCriteria to load Items
  • ItemLoadStrategy - strategy(GoF) that allows having different loading implementations of data loading. It may be database or in-memory object storage for testing. This interface obscuring the implementation of storage, letting to use predefined implementations, or implement custom.
  • ItemCriteria - is a Query Object, which is used to create declarative query. In this implementation Query Object is anemic. It does not have any behavior. It just provides API to create queries. Each loading strategy implementation will interpret the Query Object and convert to implementation specific query. In case storage is relational database, query object may construct SQL query with a help of metadata mapping class (ItemMetadataColumn).
  • ItemMetadataColumn - describes "columns" in the database. Though the implementation of storage is unknown, each property is contained in this enum, acting as a MetadataMapper pattern element from Martin Fowlers patterns.

Patterns of Enterprise Application Architecture: Martin Fowler, with Dave Rice, Matthew Foemmel, Edward Hieatt, Robert Mee, and Randy Stafford

Note: The content in this article is a summary/interpretation inspired by them. Proper attribution is given to the respective authors.

Real life Example: TypeORM

TypeORM is popular TypeScript ORM library. This library uses Repository and Query Object patterns. This is quote from the documentation typeorm.io/select-query-builder#what-is-querybuilder

QueryBuilder is one of the most powerful features of TypeORM - it allows you to build SQL queries using elegant and convenient syntax, execute them and get automatically transformed entities. Simple example of QueryBuilder:

const firstUser = await dataSource .getRepository(User) .createQueryBuilder("user") .where("user.id = :id", { id: 1 }) .getOne()

It builds the following SQL query:

SELECT user.id as userId, user.firstName as userFirstName, user.lastName as userLastName FROM users user WHERE user.id = 1 and returns you an instance of User:

Real life Example: Hibernate

Hibernate is popular ORM mapping library in Java ecosystem Hibernate_Introduction.html#queries. Hibernate utilizes Query Object pattern and took another path, and do not use Repository. Instead Query Object can create query and call database with converted query:

Is the Queries interface starting to look a lot like a DAO-style repository object? Well, perhaps. You can certainly decide to use this facility to create a BookRepository if that’s what you prefer.

// create criteria builder HibernateCriteriaBuilder builder = (HibernateCriteriaBuilder) entityManagerFactory.getCriteriaBuilder();

We’re ready to create a criteria query.

CriteriaQuery<Book> query = builder.createQuery(Book.class); Root<Book> book = query.from(Book.class); Predicate where = builder.conjunction(); if (titlePattern != null) { where = builder.and(where, builder.like(book.get(Book_.title), titlePattern)); } if (namePattern != null) { Join<Book,Author> author = book.join(Book_.author); where = builder.and(where, builder.like(author.get(Author_.name), namePattern)); } query.select(book).where(where) .orderBy(builder.asc(book.get(Book_.title)));
Related Posts
© 2025 buzzchart.info