-->
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.  [ 34 posts ]  Go to page 1, 2, 3  Next
Author Message
 Post subject: Problem in "one-to-zero-or-one" relationship
PostPosted: Fri Oct 28, 2005 4:57 pm 
Newbie

Joined: Wed Oct 06, 2004 10:34 am
Posts: 16
Location: Teresina - PI - Brasil
I've mapped a "one-to-zero-or-one" relationship as explained below:

Association: Person [1 <--> 0..1] Note

Mapping documents:
Code:
<hibernate-mapping>
   <class name="Person" table="person">
      <id name="id" column="id" type="int" unsaved-value="-1">
          <generator class="sequence">
              <param name="sequence">person_id_seq</param>
          </generator>
      </id>
      <property name="name" type="string"/>
      <many-to-one name="note" class="Note" column="id"
                   unique="true" insert="false" update="false"
                   cascade="all"/>
   </class>

   <class name="Note" table="note">
      <id name="id" column="id" type="int" unsaved-value="-1" >
          <generator class="foreign">
              <param name="property">owner</param>
          </generator>
      </id>
      <property name="note" type="string"/>
      <one-to-one name="owner" class="Person" constrained="true"/>
   </class>
   
    <query name="personFindById">
      select person from Person person
         left join fetch person.note
      where person.id = :id
    </query>
</hibernate-mapping>


Query:
Code:
select person from Person person
   left join fetch person.note
where person.id = :id


The generated SQL (show_sql=true):
Code:
select person0_.id as id5_0_,
     note1_.id as id6_1_,
     person0_.name as name5_0_,
     note1_.note as note6_1_
from person person0_
left outer join note note1_ on person0_.id=note1_.id
where person0_.id=?

PostgreSQL SQL Result:
Code:
id5_0_ | id6_1_ | name5_0_ | note6_1_
--------+--------+----------+----------
      1 |        | Regis    |
(1 row)


Hibernate version: 3.1 rc2
Name and version of the database: PortgreSQL 8.0.3

When I excute the query all persons that do not have a matching note should be null, but a note proxy is returned by Hibernate. The generated sql does the left join but the 'initialized' property in proxy (org.hibernate.proxy.CGLIBLazyInitializer) is set to 'false'. That shouldn't be happening, isn't it? Note should be null.

_________________
Regis Pires


Top
 Profile  
 
 Post subject: Bug in Hibernate
PostPosted: Mon Oct 31, 2005 6:08 pm 
Newbie

Joined: Wed Oct 06, 2004 10:34 am
Posts: 16
Location: Teresina - PI - Brasil
Can someone from Hibernate team help me with this issue? I think it is a bug in Hibernate since the result is inconsistent. It should be null but a proxy is returned.

_________________
Regis Pires


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 31, 2005 8:32 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 7:19 pm
Posts: 2364
Location: Brisbane, Australia
Not a bug at all. HIbernate 3 defaults to using proxies while H2 did not (see conversion notes). Thus you require a change to your mapping. eg,

Code:
<class name="Note" table="note" lazy="false">


Top
 Profile  
 
 Post subject: "left join fetch" should override the lazy declara
PostPosted: Tue Nov 01, 2005 8:28 am 
Newbie

Joined: Wed Oct 06, 2004 10:34 am
Posts: 16
Location: Teresina - PI - Brasil
David,
I know Hibernate 3 defaults to using proxies and that is a choice done by Hibernate 3 that I really like, but Hibernate 3 also allow us to override the lazy declaration of the mapping file using "left join fetch":
select person from Person person
left join fetch person.note
where person.id = :id


From Hibernate Reference Documentation:
Quote:
(...) a "fetch" join allows associations or collections of values to be initialized along with their parent objects, using a single select. (...) It effectively overrides the outer join and lazy declarations of the mapping file for associations and collections.

Quote:
Usually, we don't use the mapping document to customize fetching. Instead, we keep the default behavior, and override it for a particular transaction, using left join fetch in HQL. This tells Hibernate to fetch the association eagerly in the first select, using an outer join.


And the outer join really happens as the generated query shows:
select person0_.id as id5_0_,
note1_.id as id6_1_,
person0_.name as name5_0_,
note1_.note as note6_1_
from person person0_
left outer join note note1_ on person0_.id=note1_.id
where person0_.id=?


But why a proxy is still returned in note association? Shouldn't it be null as the result of the above query? Note that id6_1_ and note6_1_ are null.
Code:
id5_0_ | id6_1_ | name5_0_ | note6_1_
--------+--------+----------+----------
      1 |        | Regis    |
(1 row)

_________________
Regis Pires


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 02, 2005 5:46 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
use a <one-to-one since you're joining with the PK instead of a regulal FK

_________________
Emmanuel


Top
 Profile  
 
 Post subject: lazy "one-to-zero-or-one" relationship
PostPosted: Thu Nov 03, 2005 9:02 am 
Newbie

Joined: Wed Oct 06, 2004 10:34 am
Posts: 16
Location: Teresina - PI - Brasil
Emmanuel, thanks for your reply.

The problem is that sometimes we really need a lazy "one-to-zero-or-one" relationship. If we would change to a lazy one-to-one we would have to use the constrained attribute in 'one-to-one' element which forces a not null attribute. But sometimes a person doesn't have a note.

The use of "many-to-one" mapping that we did fits perfectly to our needs. It gets a proxy when we don't use eager fetching. It gets the right note when we use eager fetching, but it gets a proxy when there is no note associated to the person. So it works almost perfectly, except that when we force eager fetching in null notes, Hibernate hydrates person objects with a proxy and not with a null reference.

I know that I could add a FK in note table and solve my problem, but why should I do that if I can use the same person PK? If Hibernate would return null when there is no note it would be just right. I just would like that the following mapping should work as stated above. I think that when we get a proxy when an eager fetching is used is an inconsistent result. In our case, we are using a workaround to detect and fix this situation, but we wanted to report it as a way to help other people who may face the same problem and maybe to help Hibernate become even better.

Many-to-one mapping:
Code:
<many-to-one name="note" class="Note" column="id"
                   unique="true" insert="false" update="false"
                   cascade="all"/>


Our problem is not so rare. We found other people in this forum facing the same lazy "one-to-zero-or-one" problem, but the solutions were "non-lazy one-to-one mapping", "lazy not-null one-to-one mapping using constrained="true"" or "many-to-one mapping using a foreign key (FK)". We are suggesting one more solution to the problem: "many-to-one mapping using the same primary key (PK)". I hope that can help someone else.

_________________
Regis Pires


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 04, 2005 5:44 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Hibernate cannot replace a proxy with a null, this is not possible in Java wo bytecode enhancement.
So wo does hibernate know whether it needs to create a proxy or set null? The only solution is to load the second row. Check the wiki comunity area, there is a page dedicated to the non one-to-one lazyness

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 04, 2005 6:41 am 
Beginner
Beginner

Joined: Wed Oct 19, 2005 4:11 am
Posts: 48
I read somewhere in a post that you can use byte code enhancement to achieve proper lazy loading with null semantics in version 3.x. ie., no-proxy.

If you don't have a problem with byte code enhancement then this *would* be a good solution but I also read that the byte code enhancement solution is broken in 3.0.x but is fixed in 3.1.x so you'd have to be using the latest 3.1.x release candiate version to make it happen for you.

I personally am not a big fan of the proxy solution. A team I was involved with built a home grown O/R mapper back in 2001 and it had similar issues. It can also play havoc with your freedom of OO expression in modeling (which should be treasured as much as your freedom of speech!).

_________________
Chris Colman
http://stepaheadsoftware.com/products/j ... avelin.htm
Javelin: Lightweight, non intrusive, POJO, Java modeling & coding with automatic Hibernate and JDO meta data generation.
Don't forget to credit ;)


Top
 Profile  
 
 Post subject: sdf
PostPosted: Fri Nov 04, 2005 9:59 am 
Newbie

Joined: Wed Oct 06, 2004 10:34 am
Posts: 16
Location: Teresina - PI - Brasil
Emmanuel and Chrisco, thanks for your help.

But as Chrisco said, we are not fan of bytecode enhancement too. So reading and reading and (...) Hibernate Reference we decided to try the many-to-one attribute 'not-found="ignore"' and it worked!!!
So a person with no matching note has its note association set to null by Hibernate!!!
The final Person mapping is listed below:
Code:
   <class name="Person" table="person">
      <id name="id" column="id" type="int" unsaved-value="-1">
          <generator class="sequence">
              <param name="sequence">person_id_seq</param>
          </generator>
      </id>
      <property name="name" type="string"/>
      <many-to-one name="note" class="Note" column="id"
                   unique="true" insert="false" update="false"
                   not-found="ignore" cascade="all"/>
   </class>


The only difference is not-found="ignore" in note association.
So we have one more working alternative to a lazy "one-to-zero-or-one" association in Hibernate.

_________________
Regis Pires


Top
 Profile  
 
 Post subject: not-found="ignore" results in a non-lazy property
PostPosted: Fri Nov 04, 2005 4:13 pm 
Newbie

Joined: Wed Oct 06, 2004 10:34 am
Posts: 16
Location: Teresina - PI - Brasil
The use of not-found="ignore" results in a non-lazy property. So lazy "one-to-zero-or-one" in Hibernate is not possible yet. We can use non-lazy "one-to-zero-or-one" or a lazy one-to-one association.
And I undestand now that
Quote:
Hibernate cannot replace a proxy with a null, this is not possible in Java wo bytecode enhancement
.

And thank you all for help...

_________________
Regis Pires


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 04, 2005 4:29 pm 
Beginner
Beginner

Joined: Wed Oct 19, 2005 4:11 am
Posts: 48
Looks like byte code enhancement (but only if you can use >= 3.1.x) is the only option.

I don't have a problem with byte code enhancement if it makes the semantics of NULL work properly (I love using that word semantics - a lot of people who know what they're talking about use so I thought I'd give it a try!)

Like I said before if you have very realistic object models and therefore need polymorphism to function properly through a lazily fetched relationship (which proxies can't do) then byte code enhancement is your only option. I just can't wait till 3.1 release candidate gets accepted then I will use it with byte code enhancement on.

I need things to work correctly and to place no contraints on the ability of my code to express complex object models and access inheritance hierarchies polymorphically. I don't care if I have to byte enhance my code even though byte code enhancement is a blasphemus term to some in these parts.

I think the anti byte code enhancement sentiment goes back to the days of the war between Hibernate and JDO. The use of byte code enhancement seemed to be a very explosive topic in that war but that war is virtually over and Hibernate is winning so get over it everyone - it's ok to use byte code enhancement now. To the victor go the spoils - if it means your project can employ polymorphic elements without restriction and the notion of NULLs can be employed then I say "get over it and go for it!"

_________________
Chris Colman
http://stepaheadsoftware.com/products/j ... avelin.htm
Javelin: Lightweight, non intrusive, POJO, Java modeling & coding with automatic Hibernate and JDO meta data generation.
Don't forget to credit ;)


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 06, 2005 9:48 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
chrisco wrote:
I think the anti byte code enhancement sentiment goes back to the days of the war between Hibernate and JDO. The use of byte code enhancement seemed to be a very explosive topic in that war but that war is virtually over and Hibernate is winning so get over it everyone - it's ok to use byte code enhancement now. To the victor go the spoils - if it means your project can employ polymorphic elements without restriction and the notion of NULLs can be employed then I say "get over it and go for it!"


This was not a JDO/Hibernate war argument. This is a real concern we still have in the team. We do not like enhancement for very good reasons(tm).
1. Bytecode enhancement is used to lazy attributes which is usally not a good optimization.
2. Bytecode enhancement complexify/slows down you code - test cycle
3. Bytecode enhancement is less lazy than proxy in most cases. The object has to be loaded the minute you get a pointer on it.
4. Bytecode enhancement just fail to lazy public fields unless you enhance all your application/client code.

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 06, 2005 5:16 pm 
Beginner
Beginner

Joined: Wed Oct 19, 2005 4:11 am
Posts: 48
Quote:
This was not a JDO/Hibernate war argument. This is a real concern we still have in the team. We do not like enhancement for very good reasons(tm).
1. Bytecode enhancement is used to lazy attributes which is usally not a good optimization.
2. Bytecode enhancement complexify/slows down you code - test cycle
3. Bytecode enhancement is less lazy than proxy in most cases. The object has to be loaded the minute you get a pointer on it.
4. Bytecode enhancement just fail to lazy public fields unless you enhance all your application/client code.


To comment on each of your issues:

1. I agree - why would you bother lazy initializing individual attributes (unless they were hugs BLOBs or something). Most of the time I would only bother lazy fetching association relationships.

2. If my compiler can compile 100s of java files in less than a few seconds then I'm sure byte code enhancement wouldn't add that much extra time to a compile-test cycle. Besides - my keyboard needs a break to cool down ;). It would be interesting to hear from some of the people with byte code enhancement experience to find out how much extra time byte code enhancement adds.

I would judge that it is a much more serious and costly addition to the design - code - test cylce if developers can't use polymorphism through lazy fetched relationships (because lazy loading is implemented via proxies) or have issues with NULL. Not being able to correctly implement a sophisticated OO model with complex polymorphic relationships and not being able to test for NULL properly would cost my team a lot more than an extra second or so of byte code enhancement time. The later I can fix by buying faster PCs or adding more RAM the former can't be fixed and the results are a lower quality, less OO design.

3. Isn't that the definition of lazy loading anyway - it only gets fetched when you access it. Why would you access it if you didn't need it?

4. Now who would be creating public fields in this day and age anyway? :)
If you know someone who's doing that then they've probably failed "Introduction to OO Programming 1.0.1" and should immediately be sent to their "naughty spot" for 30 minutes.

_________________
Chris Colman
http://stepaheadsoftware.com/products/j ... avelin.htm
Javelin: Lightweight, non intrusive, POJO, Java modeling & coding with automatic Hibernate and JDO meta data generation.
Don't forget to credit ;)


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 06, 2005 5:48 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
Hi guys,

Just a small comment - there is *no* problem in using polymorpishm with respect to associations in hibernate. The issue you have is about representing NULL, something that is more related to the kind of datamodelling people tend to do and not OO. The users I see having problem with polymorphic associations are mostly those who want to downcast their objects which again is something that is arguable OO.

And note, that just because there *can* be a association defined between two objects, doesnt mean it *has* to be physically represented in your object model.

In any case, all is possible now with H3.1, so go buy your bigger machines ;)

/max

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 06, 2005 6:28 pm 
Beginner
Beginner

Joined: Wed Oct 19, 2005 4:11 am
Posts: 48
Thanks for your quick response Max.

Quote:
Just a small comment - there is *no* problem in using polymorpishm with respect to associations in hibernate. The issue you have is about representing NULL, something that is more related to the kind of datamodelling people tend to do and not OO.


When I have modeled -to-zero-or-one or -to-zero-or-n relationships I just want to be able to continue to code like:

Code:
    if ( insurancePolicy != null )
         insurancePolicy.makeClaim();
    else
         System.out.println("You crashed into a what?");


Where insurance policy classes are subclasses of an InsurancePolicy class - there could be a whole heap of them all implementing makeClaim in slightly different ways.

Quote:
The users I see having problem with polymorphic associations are mostly those who want to downcast their objects which again is something that is arguable OO.


Yes, well there's real OO (where every character in a string is implemented as an individually instantiated character object - eg., Smalltalk language) and there's practicle, usable OO. And sometimes in practicle, usable OO you need to downcast.

Like when you have implemented methods that, for type safety reasons (detected at compile time, not run time), take a specific subclass as a parameter.

Code:
XyzInsuranceCompany::establishXYZPolicy(XYZPolicy xyzPolicy)
{
}


You can't just pass a reference to the super class (eg., insurancePolicy) to these methods. The compiler won't let you pass the proxy in for this parameter and you won't be able to cast it either.

Quote:
And note, that just because there *can* be a association defined between two objects, doesnt mean it *has* to be physically represented in your object model.


I agree with that. If you have a one-to-one why not just merge the two objects into one... but if you have a one-to-zero-or-one then you can't merge them.

Quote:
In any case, all is possible now with H3.1, so go buy your bigger machines ;)


Kewl! So byte code enhancement is all good and stable in 3.1?

_________________
Chris Colman
http://stepaheadsoftware.com/products/j ... avelin.htm
Javelin: Lightweight, non intrusive, POJO, Java modeling & coding with automatic Hibernate and JDO meta data generation.
Don't forget to credit ;)


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 34 posts ]  Go to page 1, 2, 3  Next

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.