I've got a unidirectional one-to-one relationship on a primary key, configured as per the documentation. In other words, for every instance of object A there exists an object B with a primary key identical to that of the A instance. Instances of object B hold references to their corresponding instances of object A, but not the other way around.
I have found that when I query for object B without doing a fetch join on object A and then access A's fields through the reference on B, the proxy both fails to initialize itself and fails to indicate an error. In fact, when accessing the primary key of A through the reference on B (which is an integer), the proxy simply returns 0.
Hibernate version: 3.0.5
Mapping documents:
Note that attributes unrelated to the problem being discussed have been stripped out for clarity.
Object 'A':
Code:
<hibernate-mapping package="edu.taylor.facade.employee">
<class name="IappEmployee" table="employee">
<id name="pidm" access="field">
<generator class="assigned"/>
</id>
<property name="firstName"/>
<property name="lastName"/>
<one-to-one name="contactInfoListing" class="IappContactInfoListing"
access="edu.taylor.facade.NonExistentPropertyAccessor" />
</class>
</hibernate-mapping>
And now you're gonna say: "Hey jerk, you said it was a unidirectional relationship...and what the heck is a NonExistentPropertyAccessor??" To be honest, I'd rather not get into it, and I'm reasonably sure that it isn't related to my question. The short version is it makes certain HQL queries a lot less awkward.
Object 'B':
Code:
<hibernate-mapping package="edu.taylor.facade.employee">
<class name="IappContactInfoListing" table="contact_info_listing">
<id column="pidm" type="integer">
<generator class="foreign">
<param name="property">employee</param>
</generator>
</id>
<one-to-one name="employee" class="IappEmployee" constrained="true" access="field"/>
<property name="email"/>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():I'm using Spring, and I noticed this behavior while writing a FitNesse test, so this code might look a little confusing. Basically, I'm wrapping each instance of IappContactInfoListing in a thin wrapper class so that FitNesse can verify the contents of each class. FitNesse is a wiki-based tool for writing executable user acceptance tests, in case you're insterested.
Code:
public Set<ContactInfoListingVerifier> verifyContactInfoListings() {
TransactionTemplate txTemplate = new TransactionTemplate();
txTemplate.setTransactionManager((PlatformTransactionManager)ctx.getBean("txManager"));
return (Set<ContactInfoListingVerifier>)txTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus arg0) {
Set<ContactInfoListingVerifier> wrappedResults = new HashSet<ContactInfoListingVerifier>();
List<IappContactInfoListing> results = hibernate.find(
"from IappContactInfoListing l ");
for (IappContactInfoListing l : results) {
wrappedResults.add(new ContactInfoListingVerifier(l));
}
return wrappedResults;
}
});
}
Here's the code for the wrapper class. Once again, irrelevent attributes have been stripped for simplicity.
Code:
public class ContactInfoListingVerifier {
public int employeePidm;
public ContactInfoListingVerifier(ContactInfoListing listing) {
logger.debug("Employee instance: " + listing.getEmployee());
employeePidm = listing.getEmployee().getPidm();
}
Now, each wrapper returned by the above code has an employeePidm of 0. This is most certainly not what is stored in the DB - in the first place I've checked that the correct values are stored, and in the second, it's a primary key field!
If I change the HQL query to include a fetch join on l.employee, then the code above works as expected without any modifications. That raises a warning bell for me - unless I've broken something in the configuration, adding a fetch join should result in either no change, or a LazyInitializationException if the session has closed, but that's about it right?
Name and version of the database you are using:
SQL Server 2000