These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 
Author Message
 Post subject: Why can't I handle one-to-one relationships efficiently?
PostPosted: Fri Oct 12, 2007 2:51 pm 
Newbie

Joined: Fri Oct 12, 2007 12:23 pm
Posts: 9
Hibernate version: 3.2.5.ga

I've managed to find some odd behaviour with one-to-one relationships. I'm hoping this is because I'm not handling the mappings properly, but I basically copied them directly from the documentation.

Here's my tables / objects / hbm files:

Code:
a(id INT AUTO_INCREMENT, bId INT NOT NULL, PRIMARY KEY(id))
b(id INT AUTO_INCREMENT, PRIMARY KEY(id))

class A {
    private int id;
    private B b;
   
    // getters / setters ...
}

class B {
    private int id;
    private A a;
   
    // getters / setters ...
}

<class name="A" table="a">
  <id name="id" column="id" type="java.lang.Long">
    <generator class="native">
      <param name="sequence">global_seq</param>
    </generator>
  </id>

  <many-to-one name="b" column="bId" not-null="true" unique="true" cascade="save-update" />
</class>

<class name="B" table="b">
  <id name="id" column="id" type="java.lang.Long">
    <generator class="native">
      <param name="sequence">global_seq</param>
    </generator>
  </id>

  <one-to-one name="a" class="A" constrained="true" property-ref="b" cascade="save-update" />
</class>

Now, when I get a list of A, my log file shows n+1 selects:
Code:
org.hibernate.SQL - select this_.id as id33_6_, this_.bId as a_33_6_, b_.id as id31_1_ from a this_ inner join b b_ on this_.bId=b_.id
org.hibernate.SQL - select a_.id as id33_0_, a_.bId as a2_33_0_ from a a_ where a_.bId=?
org.hibernate.SQL - select a_.id as id33_0_, a_.bId as a2_33_0_ from a a_ where a_.bId=?
org.hibernate.SQL - select a_.id as id33_0_, a_.bId as a2_33_0_ from a a_ where a_.bId=?
...

The hibernate log suggests that it needs to "initialize the entity" in those extra selects:
Code:
org.hibernate.loader.Loader - result set row: 0
org.hibernate.loader.Loader - result row: EntityKey[B#8117], EntityKey[A#18877]
org.hibernate.loader.Loader - result set row: 1
org.hibernate.loader.Loader - result row: EntityKey[B#8118], EntityKey[A#18878]
org.hibernate.loader.Loader - result set row: 2
org.hibernate.loader.Loader - result row: EntityKey[B#8119], EntityKey[A#18879]
...
org.hibernate.engine.TwoPhaseLoad - resolving associations for [B#8117]
org.hibernate.loader.Loader - loading entity: [A#8117]
org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
org.hibernate.jdbc.AbstractBatcher - about to open ResultSet (open ResultSets: 0, globally: 0)
org.hibernate.loader.Loader - result set row: 0
org.hibernate.loader.Loader - result row: EntityKey[A#18877]
org.hibernate.jdbc.AbstractBatcher - about to close ResultSet (open ResultSets: 1, globally: 1)
org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
org.hibernate.loader.Loader - done entity load
org.hibernate.engine.TwoPhaseLoad - done materializing entity [B#8117]
org.hibernate.engine.TwoPhaseLoad - resolving associations for [A#18877]
org.hibernate.engine.TwoPhaseLoad - done materializing entity [A#18877]
org.hibernate.engine.TwoPhaseLoad - resolving associations for [B#8118]
org.hibernate.loader.Loader - loading entity: [A#8118]
org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
org.hibernate.jdbc.AbstractBatcher - about to open ResultSet (open ResultSets: 0, globally: 0)
org.hibernate.loader.Loader - result set row: 0
org.hibernate.loader.Loader - result row: EntityKey[A#18878]
org.hibernate.jdbc.AbstractBatcher - about to close ResultSet (open ResultSets: 1, globally: 1)
org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
org.hibernate.loader.Loader - done entity load
org.hibernate.engine.TwoPhaseLoad - done materializing entity [B#8118]
org.hibernate.engine.TwoPhaseLoad - resolving associations for [A#18878]
org.hibernate.engine.TwoPhaseLoad - done materializing entity [A#18878]
org.hibernate.engine.TwoPhaseLoad - resolving associations for [B#8119]
org.hibernate.loader.Loader - loading entity: [A#8119]
org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
org.hibernate.jdbc.AbstractBatcher - about to open ResultSet (open ResultSets: 0, globally: 0)
org.hibernate.loader.Loader - result set row: 0
org.hibernate.loader.Loader - result row: EntityKey[A#18879]
org.hibernate.jdbc.AbstractBatcher - about to close ResultSet (open ResultSets: 1, globally: 1)
org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
org.hibernate.loader.Loader - done entity load
org.hibernate.engine.TwoPhaseLoad - done materializing entity [B#8119]
org.hibernate.engine.TwoPhaseLoad - resolving associations for [A#18879]
org.hibernate.engine.TwoPhaseLoad - done materializing entity [A#18879]
...

Any reason why hibernate thinks it must select again for object a, when it could get that information from the original query? I've found that if I add a fetch="join" to the many-to-one relationship, it just performs this select:
Code:
select ... from a inner join b left outer join a

Ideally, I would like to remove any re-querying or joining of table a. Thanks for your help!


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 12, 2007 3:05 pm 
Newbie

Joined: Fri Oct 12, 2007 12:23 pm
Posts: 9
I've been going through the hibernate code to try to figure out what's going on. It seems like it's trying to populate the field (B.a) from a "unique key cache" on the session. Unfortunately, this cache is empty.

There is one place that the Loader populates this cache: in loadFromResultSet. The following line always seems to return "null" for me:

Code:
String ukName = ownerAssociationTypes[i].getRHSUniqueKeyPropertyName();

However, if I change ukName to "b" using my debugger, everything works!

I know I'm getting a little esoteric here; any ideas whether I'm going down the right path?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 15, 2007 9:54 am 
Newbie

Joined: Fri Oct 12, 2007 12:23 pm
Posts: 9
Hmmmm.... no bites.

Well, if anybody else has this problem, I'm afraid you'll find our solution most unsatisfying. We're taking advantage of the fact that whenever we need a list of A, we will not change any of the objects; it is read only.

So, we used a view to merge the tables in SQL, and load them all into a new object called AB.
Corey


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 15, 2007 9:55 am 
Newbie

Joined: Fri Oct 12, 2007 12:23 pm
Posts: 9
Hmmmm.... no bites.

Well, if anybody else has this problem, I'm afraid you'll find our solution most unsatisfying. We're taking advantage of the fact that whenever we need a list of A, we will not change any of the objects; it is read only.

So, we used a view to merge the tables in SQL, and load them all into a new read-only object called AB.
Corey


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.