Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA fetching one to many

I have the following entities: Event and Attribute. An event can have many attributes.

The problem I am having is, I can't seem to find a query that returns the events with their attributes in a single SQL query. I could have millions of events that need to be iterated through and I don't want to lazy load them all for obvious performance reasons.

I've tried using fetch in the query, but it returns an event for every attribute. i.e. if an event had 2 attributes it would return 2 events each with one attribute.

What I want is one event with 2 attributes.

SELECT e FROM Event e LEFT JOIN FETCH e.attributes

If I add DISTINCT it works, but then it creates a distinct SQL query which is extremely slow over large data sets.

public class Event {
  @OneToMany(mappedBy = "event", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
  public Set<Attribute> getAttributes(){}
}

public class Attribute {
    @ManyToOne(cascade=CascadeType.ALL)
    @JoinColumn(name = "event_id", nullable = false)
    public Event getEvent() {
        return event;
    }
}

Solution

I couldn't find a JPA solution. Instead, I unwrapped the EntityManager to the Hibernate session and used the criteria's result transformer as @milkplusvellocet suggested. This retrieves distinct root entities without creating a distinct SQL query.

Session session = em.unwrap(Session.class);
Criteria criteria = session.createCriteria(Event.class);
criteria.setFetchMode("attributes", FetchMode.JOIN);

criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);  

One thing to note is, I tried using HQL from the unwrapped session. I added DISTINCT to the query and set the result transformer to DISTINCT_ROOT_ENTITY similar to the criteria solution above. Doing it this way still created a distinct SQL query.

like image 451
kevingallagher Avatar asked Apr 12 '12 21:04

kevingallagher


People also ask

How does JPA handle one-to-many relationships?

The One-To-Many mapping comes into the category of collection-valued association where an entity is associated with a collection of other entities. Hence, in this type of association the instance of one entity can be mapped with any number of instances of another entity.

How do you fetch a one-to-many DTO projection with JPA and Hibernate?

Fetching a one-to-many DTO projection with JPA and Hibernate. The postDTOMap is where we are going to store all PostDTO entities that, in the end, will be returned by the query execution. The reason we are using the postDTOMap is that the parent rows are duplicated in the SQL query result set for each child record.

What is the default fetch mode for one-to-many association in Hibernate JPA?

EAGER . By default, @OneToMany and @ManyToMany associations use the FetchType. LAZY strategy while the @OneToOne and @ManyToOne use the FetchType. EAGER strategy instead.


1 Answers

You need a ResultTransformer.

Try the following HQL:

SELECT DISTINCT e FROM Event e LEFT JOIN FETCH e.attributes

This is equivalent to using CriteriaSpecification.DISTINCT_ROOT_ENTITY in a criteria query.

like image 122
darrengorman Avatar answered Oct 16 '22 00:10

darrengorman