6

I am learning Domain Driven Design and I cannot understand the difference between Repository and DAO. It seems to me that they are similar. Their roles and functionalities are the same, but why they have different names? I have read many articles and blog posts, but I couldn't find the answer.

Update

The most references about Repository and DAO describe the characteristics of two concepts and compare them, but my point is differences.

8
  • DAO = Data Access Object
    – L.A
    Apr 30, 2022 at 19:14
  • 2
    Well, I don't know which search keywords you tried, but googling "repository difference DAO" gave me this at the top: baeldung.com/java-dao-vs-repository
    – Doc Brown
    Apr 30, 2022 at 19:20
  • 1
    Or, cross-site duplicate: stackoverflow.com/questions/8550124/… . Though I am surprised that I could not find a good duplicate target on this site, it seems to be a relevant software engineering question. Apr 30, 2022 at 19:34
  • 3
    Eric Evans doesn’t mention DAO / Data Access Objects in the blue book. Still a good question, but not specifically related to DDD imo.
    – Rik D
    Apr 30, 2022 at 20:17
  • 2
    @RobertHarvey, I read the first reference you have mentioned ,the second one is about DTO not DAO. DTO and DAO are completely different concepts.
    – L.A
    May 1, 2022 at 3:14

2 Answers 2

9

The critical difference between the Repository pattern and the Data Access Object pattern is that the former deals with domain concepts, while the latter deals with technology-specific implementation details.

A Repository interface lives within your domain layer, and thus is defined using the terms in your ubiquitous language. More specifically, the repository deals with an aggregate root and serves as an abstraction over the manipulation of a collection of aggregate roots.

interface OrderRepository {
  Collection<Order> findAll();
  void save(Order order);
  void delete(Order order);
}

Notice that this interface is not coupled to any persistence technology: it simply defines the actions.

The implementation of the Repository, as in the concrete type which implements the methods defined in the interface, must of course be specific to a certain technology. However, the implementation details of how the aggregate roots is mapped to and from technology-specific structures is abstracted away from your domain layer. Concretely, the implementation would not live within your domain layer, and would instead be defined in a separate package from which your domain layer does not have access. An example implementation could look like this:

class PostgresOrderRepository implements OrderRepository {
  @Override
  public Collection<Order> findAll() {
    Collection<PostgresOrderEntity> orderEntity = getOrdersFromOrderTable();
    Collection<PostgresClientEntity> clientEntity = getClientsFromClientTable();
    Collection<Order> orders = constructDomainOrderObjectsFromPostgresEntities(...);
    return orders;
  }
  // ...
}

The implementation is responsible to orchestrate the retrieval of the data from PostgreSQL, and it knows from which tables to do so. Once it has all the PostgreSQL entities, it can construct the aggregate root and return it, which means that clients of the repository never have to know what happened under the hood.

For a simple repository, it may be enough to define an implementation which interacts directly with the database tables. There can come a time however where a repository deals with a large number of different tables, all of which support many different queries. Defining every of these operations in a single implementation of a repository may end up dramatically increase its size and complexity. It can be helpful to encapsulate the operations on a single table in a DAO.

The DAO deals with a specific technology and, usually, over a single collection (such as a table in a relation database management system). It does not work with aggregate roots and domain concepts, only technology-specific entities.

class PostgresOrderDao {
  public Collection<PostgresOrderEntity> selectAll() {
    var query = "SELECT * FROM order";
    var rows = connection.query(query);
    return rows.stream().map(PostgresOrderEntity::fromRow).toList();
}

The logic as to how to retrieve the data, such as which table it is persisted to, or how to interpret the value of each column, is encapsulated within this implementation. In practice, you will often have one DAO class per table.

Once a DAO implementation is defined, you can use it in the implementation of your repository, which may simplify it a great deal:

class PostgresOrderRepository implements OrderRepository {
  // ...
  @Override
  public Collection<Order> findAll() {
    Collection<PostgresOrderEntity> orderEntity = orderDao.selectAll();
    Collection<PostgresClientEntity> clientEntity = clientDao.selectAll();
    Collection<Order> orders = constructDomainOrderObjectsFromPostgresEntities(...);
    return orders;
  }
  // ...
}

Your implementation of the repository may then be composed with as many DAOs as it needs.

In short,

  • The interface of a Repository is defined from your ubiquitous language and is technology-agnostic;
  • The implementation of this technology-specific and is responsible for converting to and from your aggregate roots and the technology-specific entities;
  • A DAO is technology-specific and deals directly with the technology-specific entities, being only responsible for operations over a collection such as a PostgreSQL table.
0

'Repositories are more coarse-grained than DAOs by providing control of an entire Aggregate Root (AG) often hiding a lot of internal state from the client. DAO's on the other hand can be as fine-grained as being dedicated to a single entity object'. Source

Your Answer

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

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