I have the following entities:
//The class Entity is a @MappedSuperclass with id, audit fields, equals and so on.
@Entity
public class Foo extends Entity {
@OneToMany(mappedBy = "foo", cascade=CascadeType.ALL, fetch = FetchType.LAZY)
private Set<Bar> bars = new HashSet<Bar>; // + getter/setter
// ... other properties
}
@Entity
public class Bar extends Entity {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "foo_id")
private Foo foo; // +getter/setter
@OneToOne(cascade=CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "baz_id", nullable = false)
private Baz baz; // + getter/setter
// ... other properties
}
@Entity
public class Baz extends Entity {
@OneToOne(mappedBy = "baz", fetch = FetchType.LAZY, optional = false)
private Bar bar; // + getter/setter
// ... other properties
}
Now if I load a Bar
with the following, all is well (i.e. only one query is sent to the DB):
SELECT bar FROM Bar bar LEFT JOIN FETCH bar.baz WHERE bar.id = :barId
However, If I do either of the following, a new SELECT
is created for every Baz
to get the associated Bar
object:
SELECT f FROM Foo f LEFT JOIN FETCH f.bars bar LEFT JOIN FETCH bar.baz WHERE f.id = :fooId
SELECT f FROM Foo f LEFT JOIN FETCH f.bars bar LEFT JOIN FETCH bar.baz baz LEFT JOIN FETCH baz.bar WHERE f.id = :fooId
The output is:
10:52:08,622 INFO [STDOUT] Hibernate: select ... from Foo ...
10:52:08,698 INFO [STDOUT] Hibernate: select ... from Bar where baz_id=?
10:52:08,711 INFO [STDOUT] Hibernate: select ... from Bar where baz_id=?
... and so on
Now, I understand from this answer that @OneToOne
has problems with lazy loading, so I followed their advice and added optional = false (which didn't seem to do much for me).
I also tried suggestion 3 from this blogpost, but that seems to have no effect at all..
Any suggestions how to eagerly fetch the object graph to avoid the SELECT n+1 issue?
I use EJB 3 (JPA 1) with Hibernate 3.2.4.sp1 on a JBoss 4.2 server.
NOTE: This is somewhat analogous to one of my previous questions. The difference is that here Baz
has a reference back to Bar
which seems to be the issue.