Browse Java Design Patterns & Enterprise Application Architecture

DAO in ORM Frameworks (Hibernate and JPA)

Use DAO with Hibernate or JPA when the extra boundary adds clarity around queries and persistence behavior instead of wrapping the ORM mechanically.

Hibernate and JPA change the DAO conversation. Once a framework already abstracts SQL and unit-of-work behavior, a DAO must justify itself by adding clarity, not by blindly wrapping every repository call.

What The ORM Already Gives You

Hibernate and JPA already provide:

  • mapping between objects and relational data
  • query APIs
  • identity and unit-of-work behavior
  • transaction participation

That means a DAO in an ORM-based system should not exist just to rename EntityManager calls.

When A DAO Still Helps

A dedicated DAO still makes sense when it:

  • centralizes nontrivial queries
  • hides ORM-specific APIs from upper layers
  • groups persistence operations around a meaningful aggregate or use case
  • isolates fetch strategy or mapping concerns that should not leak upward

In those cases, the DAO is not redundant. It is a deliberate persistence boundary on top of the ORM.

When It Does Not Help

The extra layer is usually weak when:

  • every DAO method forwards directly to a repository or entity manager
  • the DAO adds no naming improvement or query isolation
  • services still know ORM-specific details anyway
  • the project already has a simpler repository abstraction that fits better

At that point the DAO often survives only because the team assumes it belongs in every “enterprise Java” design.

A Practical Example

 1public final class JpaInvoiceDao implements InvoiceDao {
 2    private final EntityManager entityManager;
 3
 4    public JpaInvoiceDao(EntityManager entityManager) {
 5        this.entityManager = entityManager;
 6    }
 7
 8    @Override
 9    public List<InvoiceSummary> findOutstandingByCustomer(CustomerId customerId) {
10        return entityManager.createQuery(
11                """
12                select new com.example.InvoiceSummary(i.id, i.total, i.dueDate)
13                from InvoiceEntity i
14                where i.customerId = :customerId
15                  and i.status = :status
16                """,
17                InvoiceSummary.class
18            )
19            .setParameter("customerId", customerId.value())
20            .setParameter("status", InvoiceStatus.OUTSTANDING)
21            .getResultList();
22    }
23}

This DAO earns its existence because it concentrates a meaningful query and returns a type the service actually needs.

Design Review Questions

When reviewing DAO with Hibernate or JPA, ask:

  • Does this DAO isolate meaningful persistence behavior?
  • Is it reducing ORM leakage into services?
  • Would a repository or direct framework abstraction be simpler?
  • Are fetch and query decisions owned in one place or scattered?

With ORM frameworks, DAO should be earned. If it adds no clear boundary, remove the ceremony rather than defend it with tradition.

Revised on Thursday, April 23, 2026