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: Does Hibernate support optional one-to-one associations?
PostPosted: Tue Aug 15, 2006 5:40 am 
Newbie

Joined: Wed May 17, 2006 8:26 am
Posts: 8
Location: Amsterdam
Hello,

I am trying to figure out if Hibernate supports optional one-to-one associations, e.g. Person (0..1) -- (0..1) House and so far am not finding anything.

The Hibernate books and reference all talk of two ways of mapping one-to-one associations:
1. using a many-to-one fk association with a unique constraint on the fk;
2. using a pk association.

the trouble with both of them is that they enforce the mandatory property of an association end, which sometimes is not desirable. One enforces the mandatory property with the uniqueness constraint on the fk, the other using the fact that one table's pk is its fk.

I tried to see if I could adapt the 1st way of representing one-to-ones to
support optional association ends. What I did was simply remove the unique and not null constrains from DDL generated (without removing it it would be impossible to have a Person record that doesn't reference a passport record):

from
Code:
CREATE TABLE Person (
PassUniqueId                   VARCHAR (32)                NOT NULL,
version                        INTEGER                       NOT NULL,
uniqueId                       VARCHAR (32)                   NOT NULL,
name                           VARCHAR (40)                   NULL,
PRIMARY KEY (uniqueId),
UNIQUE(PassUniqueId),
FOREIGN KEY (PassUniqueId) REFERENCES Passport (uniqueId)
);


to
Code:
CREATE TABLE Person (
PassUniqueId                   VARCHAR (32)                NULL,
version                        INTEGER                       NOT NULL,
uniqueId                       VARCHAR (32)                   NOT NULL,
name                           VARCHAR (40)                   NULL,
PRIMARY KEY (uniqueId),
FOREIGN KEY (PassUniqueId) REFERENCES Passport (uniqueId)
);


but leave the uniqueness attribute in the mapping file:
Code:
        <many-to-one
            name="pass"
            class="application.business.logic.Passport"
            cascade="save-update,merge"
            unique="true"
        >
            <column name="PassUniqueId"/>
        </many-to-one>


The resulting solution worked fine and I was able to create instances of Person not linked to a Passport. However Hibernate didn't succed in keeping the association from degrading into a many-to-one. It enabled me to create two Persons linked with the same Passport:

Code:
PASSUNIQUEID    | VIRSION | UNIQUEID    | Name
================================================
0d8b3919fffff   | 1       | 0d5fb1dcfff | John
0d8b3919fffff   | 0       | 10fd07bdfff | Sam


A subsequent attempt at retrieving such Persons with Hibernate failed:
org.hibernate.HibernateException: More than one row with the given identifier was found: 0d8b3919ffffffd60151e135b6da0164, for class: application.business.logic.Passport.

Is there a way to configure hibernate to keeping the association from degrading into a many-to-one without relying on an RDBMS engine?

Hibernate version: 3.2.CR2

Thank you,
Andrei.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 15, 2006 8:33 am 
Senior
Senior

Joined: Tue Mar 09, 2004 2:38 pm
Posts: 141
Location: Lowell, MA USA
If you use a PK association so that your Passport shares the same PK as your Person instance, you should use the FK ID generator in the Passport mapping:

Code:
<id name="passportId">
  <column name="PassId" />
         <generator class="foreign">
               <param name="property">person</param>
          </generator>
</id>

<one-to-one name="person" class="Person" constrained="true" /> 


The Passport mapping uses the person reference to derive it's PK. Then, in your Person mapping, you continue to use the many-to-one association, but adding a not-found="ignore" attribute so that it won't throw an exception when a passport is not found for Persons without a passport:

Code:
<many-to-one
            name="pass"
            class="application.business.logic.Passport"
            cascade="save-update,merge"
            unique="true"
            not-found="ignore"
        >
            <column name="PassportId"/>
        </many-to-one>


I have found not-found="ignore" to be non-performant as it disbaled batch-fetching on the related entity. There are two ways I get around that:

Code:
<many-to-one
            name="pass"
            class="application.business.logic.Passport"
            cascade="save-update,merge"
            unique="true"
            formula="(select p.passportId from Passport where p.personId = personId)"
        >
        </many-to-one>


Or, use fetch="join"

Code:
<many-to-one
            name="pass"
            class="application.business.logic.Passport"
            cascade="save-update,merge"
            unique="true"
            fetch="join"
            not-found="ignore"
        >
            <column name="PassportId"/>
        </many-to-one>


Hope this helps.

Ryan-

_________________
Ryan J. McDonough
http://damnhandy.com

Please remember to rate!


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 15, 2006 8:51 am 
Newbie

Joined: Wed May 17, 2006 8:26 am
Posts: 8
Location: Amsterdam
Ryan, thank you very much for your time and the reply. Our problem is that we cannot use the pk mapping (Passport shares the same pk instance as Person). We really need to figure out a way to get optional one-to-one associations to work with the fk mapping. My mapping file for passport looks as follows:
<class
name="application.business.logic.Passport"
table="Passport"
optimistic-lock="version"
mutable="true"
>

<id
name="id"
column="uniqueId"
type="string">
<generator class="assigned"/>
</id>

...
...


<!-- Bi-directional one-to-one association to entity: Person. -->
<one-to-one
name="person"
class="application.business.logic.Person"
cascade="save-update,merge"
constrained="false"
property-ref="pass"
>

As I mentioned previously we got everything to work with the many-to-one fk association. The main trouble is that we discover that Hibernate puts no effort into ensuring that the association doesn't degrade into a many-to-one and seems to rely soly on the RDBMS and the UNIQUE DDL constraint for that matter.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 16, 2006 8:42 am 
Newbie

Joined: Wed May 17, 2006 8:26 am
Posts: 8
Location: Amsterdam
FYI: I got convinced that optional one-to-one associations are simply not properly supported in Hibernate and created a bug report for it: http://opensource.atlassian.com/projects/hibernate/browse/HHH-2007.


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.