Skip to main content

Introduction

··397 words·2 mins

JPA - JPQL - DAO
#

The goal of this phase was to make the persistence layer reflect the real domain: users, register, products. Registrations may have receipts, and products have warranties. I implemented JPA mappings between User, Product, ProductRegistration, Receipt, and Warranty, then built a DAO layer that standardizes CRUD operations through IDAO<T> and uses JPQL for queries that traverse relationships (implemented in RetrieveDAO and selected methods in UserDAO/SecurityDAO).

A key focus was avoiding overly complex objects: data are handled explicitly (for example with JOIN FETCH when needed), and delete behavior is handled deliberately to avoid unintended cascades.

public User getByIDWithRegistrations(Long id) {
    try (EntityManager em = emf.createEntityManager()) {
        try {
            return em.createQuery(
                "SELECT DISTINCT u FROM User u " +
                "LEFT JOIN FETCH u.registrationlist " +
                "WHERE u.id = :id",
                        User.class)
                        .setParameter("id", id)
                        .getSingleResult();
        } catch (NoResultException e) {
            throw new EntityNotFoundException("No entity found with id: " + id);
        }
    }
}

Issues related to retrieving users with or without a registrationlist caused LazyInitializationException when trying to retrieve users with a registrationlist, using LEFT JOIN FETCH ensures that a user is still returned even if the specific user has no registrationlist.

What
#

Implemented the persistence layer using JPA by defining the entities User, Product, ProductRegistration, Receipt, and Warranty, along with their relationships. A DAO structure was introduced through IDAO<T>, with concrete implementations such as RetrieveDAO, UserDAO, and SecurityDAO.

Custom JPQL queries were added to handle relational data, including getByIDWithRegistrations(Long id), which uses LEFT JOIN FETCH to retrieve a User together with its registrationlist.

Why
#

The main problem was ensuring reliable retrieval of related data without encountering LazyInitializationException, while keeping the domain model simple and maintainable. There was also a need to avoid excessive cascading and unintended side effects in persistence operations.

Constraints included maintaining clear entity relationships, ensuring predictable data access for API use, and supporting testability without overly complex configurations.

Design reasoning (tradeoffs)
#

AspectDescription
ChoiceUse explicit JPQL queries with JOIN FETCH for controlled loading of relationships
Alternative(s)Default fetch types (EAGER / LAZY) and cascading strategies
Not chosenDefault strategies can cause inefficient queries or LazyInitializationException, while cascading may introduce unintended persistence operations
Risks downsidesMore verbose queries and tighter coupling between query logic and entities
MitigationsCentralize query logic in DAO classes and reuse methods for consistency
Next stepIntroduce DTOs to handle larger datasets and improve performance