Question

I have the following JPA Entity:

@Entity
@Table(name = "app")
public class App {

    @Id
    private String id;

    @OneToOne(mappedBy = "app")
    @PrimaryKeyJoinColumn
    private FileDetails fileDetails;

    @ManyToOne
    private Developer developer;

    @ManyToOne
    @JoinColumn(name = "category_id")
    private Category category;

    @OneToMany(mappedBy = "app", fetch = FetchType.EAGER)
    private List<Image> images;

    //getters, setters
}

As you can see the Image entity is set to EAGER fetching. I want to select all entities using pagination and my Generic DAO uses this method:

public List<T> findByPage(int pageNum, int pageSize) {
        CriteriaQuery<T> cq = getEntityManager()
                .getCriteriaBuilder().createQuery(entity);
        cq.select(cq.from(entity));

        int firstResult = pageNum * pageSize;
        return getEntityManager().createQuery(cq)
                .setFirstResult(firstResult)
                .setMaxResults(pageSize)
                .getResultList();
}

However when I run the query I have a N+1 in relation to the Image entity. So for each App selected I get N selects for the number of Images. Isnt EAGER fetching supposed to solve this problem? And what could be a solution?

Was it helpful?

Solution

IIRC, a join (fetch) to Image in that query would solve such problem.

Now, as you need to specify the Image class, I'll show you a non-generic solution, so you can verify if it works.

// notice I changed all <T> to <App>
public List<App> findByPage(int pageNum, int pageSize) {
        CriteriaQuery<App> cq = getEntityManager()
                .getCriteriaBuilder().createQuery(entity);

        Root<App> root = query.from(App.class); // added this
        root.fetch("app");                      // added this, this is the join

        cq.select(cq.from(entity));

        int firstResult = pageNum * pageSize;
        return getEntityManager().createQuery(cq)
                .setFirstResult(firstResult)
                .setMaxResults(pageSize)
                .getResultList();
}

I'm not 100% on this (I have't tested, and don't know if the "app" string is the right way -- it should be the field which you want to "pull", but as this is many to one, I'm unsure, and placed the field in Image that refers to App instead), but I think the solution is somewhere around a join and hopefully this points in the right direction.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top