javamysqlxmlhibernatehbm

Strange behavior on one-to-one and many-to-one (unique=true) fetching in hibernate


I'm trying to achieve lazy load on the following.

User.java

public class User {

    private int id;
    private String userName;
    private String password;
    private Employee employee;

    //getter and setters

}

User.hbm.xml

<hibernate-mapping>
    <class name="com.site.dto.User" table="user">
        <id name="id" type="java.lang.Integer">
            <column name="id" />
            <generator class="identity" />
        </id>
        <property name="userName" type="string" update="false">
            <column name="user_name" length="50" not-null="true" unique="true" />
        </property>
        <property name="password" type="string">
            <column name="password" length="50" not-null="true" unique="true" />
        </property>
        <one-to-one name="employee" class="com.site.dto.Employee" fetch="select" cascade="save-update" />
    </class>
</hibernate-mapping>

Employee.java

public class Employee implements Serializable{

    private int id;
    private String name;
    private String email;
    private User user;

    // getter and setters

}

Employee.hbm.xml

<hibernate-mapping>
    <class name="com.site.dto.Employee" table="employee">
        <id name="id" type="java.lang.Integer">
            <column name="id" />
            <generator class="identity" />
        </id>
        <property name="name" type="string">
            <column name="name" length="50" not-null="true" unique="true" />
        </property>
        <property name="email" type="string" update="false">
            <column name="email" length="50" not-null="true" unique="true" />
        </property>

        // enforcing many-to-one to one-to-one by putting unique="true"
        <many-to-one name="user" column="user_id" class="com.site.dto.User" unique="true" not-null="true" fetch="select" cascade="save-update" />
    </class>
</hibernate-mapping>

First I'm getting the User Object based on username. Now I'm trying to load the employee object which gives me null pointer exception. So after digging on some debug, it seems to be using a select statement with wrong where clause. Here is the hibernate debug

select employee0_.id as id1_1_0_, employee0_.name as name2_1_0_, employee0_.email as email3_1_0_,employee0_.user_id as user_id25_1_0_, from employee employee0_ where employee0_.id=?

Why is the where clause is based on employee.id and not employee.user.id ? I think this is due to the reason on how one-to-one mapping works in hbm.xml configuration where one-to-one will be linked to child table's primary key id but not user_id. I'm forcing the many-to-one to one-to-one in employee by using unique="true". I can fetch the employee in Hibernate annotation's one-to-one by defining @Join-column but I can't figure out how to map the one-to-one in hbm.xml which should refer the child's user_id.


Solution

  • Figured out the solution a while back, but forget to post it.

    The above problem is coz, by default one-to-one mapping will be implemented for a child table which have the parent's primary key as the Child's primary key. So if we're going to eliminate that default property and use one-to-one with many-to-one (unique=true), we should define property-ref

    I've added property-ref in one-to-one mapping in User.hbm.xml and now it works fine.

    <one-to-one name="employee" property-ref="user" class="com.site.dto.Employee" fetch="select" cascade="save-update" />