I have found a lot of threads on this but none with any resolution of the issue.
Succinctly, the problem is that with one-to-one bidirectional associations Hibernate for some reason will retrieve the other end of the association individually for each entity returned, i.e. you get n+1 selects. Yuck.
I'm running Hibernate 3.6.0 (on MySQL, but I don't think that matters). My model is:
Code:
@Entity
class Parent {
@Id @GeneratedValue
private long id;
@OneToOne( mappedBy = "parent" )
private Child child;
}
@Entity
class Child {
@Id @GeneratedValue
private long id;
@OneToOne( optional = false )
@JoinColumn( name = "parent_id" )
private Parent parent;
}
(getters and setters omitted for brevity)
Let's say I do something nice and simple like:
Code:
session.createQuery("from Parent").list();
I would expect to see a query like "select * from Parent left outer join Child on Parent.id = Child.parent_id", which gets us everything we need. Instead, Hibernate does this:
Hibernate: select parent0_.id as id12_ from Parent parent0_
Hibernate: select child0_.id as id13_1_, child0_.parent_id as parent2_13_1_, parent1_.id as id12_0_ from Child child0_ inner join Parent parent1_ on child0_.parent_id=parent1_.id where child0_.parent_id=?
Hibernate: select child0_.id as id13_1_, child0_.parent_id as parent2_13_1_, parent1_.id as id12_0_ from Child child0_ inner join Parent parent1_ on child0_.parent_id=parent1_.id where child0_.parent_id=?
Hibernate: select child0_.id as id13_1_, child0_.parent_id as parent2_13_1_, parent1_.id as id12_0_ from Child child0_ inner join Parent parent1_ on child0_.parent_id=parent1_.id where child0_.parent_id=?
Hibernate: select child0_.id as id13_1_, child0_.parent_id as parent2_13_1_, parent1_.id as id12_0_ from Child child0_ inner join Parent parent1_ on child0_.parent_id=parent1_.id where child0_.parent_id=?
Hibernate: select child0_.id as id13_1_, child0_.parent_id as parent2_13_1_, parent1_.id as id12_0_ from Child child0_ inner join Parent parent1_ on child0_.parent_id=parent1_.id where child0_.parent_id=?
i.e. let's get a list of all of the parents (there are 5 in the database), and then individually select each child.
Similar behavior happens for "from Child", but even worse - there are now TWO queries for each of the four children:
Hibernate: select child0_.id as id13_, child0_.parent_id as parent2_13_ from Child child0_
Hibernate: select parent0_.id as id12_1_, child1_.id as id13_0_, child1_.parent_id as parent2_13_0_ from Parent parent0_ left outer join Child child1_ on parent0_.id=child1_.parent_id where parent0_.id=?
Hibernate: select child0_.id as id13_1_, child0_.parent_id as parent2_13_1_, parent1_.id as id12_0_ from Child child0_ inner join Parent parent1_ on child0_.parent_id=parent1_.id where child0_.parent_id=?
Hibernate: select parent0_.id as id12_1_, child1_.id as id13_0_, child1_.parent_id as parent2_13_0_ from Parent parent0_ left outer join Child child1_ on parent0_.id=child1_.parent_id where parent0_.id=?
Hibernate: select child0_.id as id13_1_, child0_.parent_id as parent2_13_1_, parent1_.id as id12_0_ from Child child0_ inner join Parent parent1_ on child0_.parent_id=parent1_.id where child0_.parent_id=?
Hibernate: select parent0_.id as id12_1_, child1_.id as id13_0_, child1_.parent_id as parent2_13_0_ from Parent parent0_ left outer join Child child1_ on parent0_.id=child1_.parent_id where parent0_.id=?
Hibernate: select child0_.id as id13_1_, child0_.parent_id as parent2_13_1_, parent1_.id as id12_0_ from Child child0_ inner join Parent parent1_ on child0_.parent_id=parent1_.id where child0_.parent_id=?
Hibernate: select parent0_.id as id12_1_, child1_.id as id13_0_, child1_.parent_id as parent2_13_0_ from Parent parent0_ left outer join Child child1_ on parent0_.id=child1_.parent_id where parent0_.id=?
Hibernate: select child0_.id as id13_1_, child0_.parent_id as parent2_13_1_, parent1_.id as id12_0_ from Child child0_ inner join Parent parent1_ on child0_.parent_id=parent1_.id where child0_.parent_id=?
If I say "from Parent as parent left join fetch parent.child", I get the behavior I expected:
Hibernate: select parent0_.id as id12_0_, child1_.id as id13_1_, child1_.parent_id as parent2_13_1_ from Parent parent0_ left outer join Child child1_ on parent0_.id=child1_.parent_id
Okay, fine, it's somewhat obnoxious to have to make sure I left join fetch the child in every query (especially if there are multiple one-to-one associations), but whatever. There should be a better way to do this. And I still haven't figured out how to do this for Child - the analogous query only cuts the number of queries by half. I want to do this in
one query.
Does
anyone know why this happens, and a consistent way to prevent it?
PS: I don't care about lazily loading child, as many of the other people posting about this do - I just don't want to run one query for each row in my table!