-->
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.  [ 12 posts ] 
Author Message
 Post subject: Hibernate <set> return null for one-to-many mapping
PostPosted: Mon Feb 20, 2006 8:48 am 
Newbie

Joined: Mon Feb 20, 2006 8:19 am
Posts: 5
Problem
I want to use one-to-many mapping to return a set. In User HBM, I want to return a cashSet in a user object. The abstract is

Code:
        <!-- Set and One-to-Many Mapping to Cash -->
        <set name="cashList" inverse="true">
            <key column="userID"/>
            <one-to-many class="com.cyproj.pm.db.Cash"/>
        </set>
        <!-- End of One-to-Many -->


The database is set correct and working. When I connect using debug mode of Netbean, I can see that the cashList and all other set return null when there is value in the database. The other values return successfully, for example, one-to-one mapping do return valid value. My log and hibernate log did not show any error too.

What had I gone wrong or missed out? I am new to hibernate. I had also searched and tried the result in Google, but to no help... Please help me.

I had provided my finance.hbm.xml, user.hbm.xml and the hibernate session code. Please point out any error or any pointer that I should take note. Thanks

Hibernate version: 3.1

Mapping documents:

User HBM

Code:
<hibernate-mapping package="com.cyproj.pm.db">
    <!-- Users Class -->
    <class name="User" table="User" >
        <id name="id" type="int" unsaved-value="0">
            <generator class="identity"/>
        </id>
        <property name="loginID" type="string" unique="true" not-null="true"/>
        <property name="password" type="string" not-null="true"/>
        <property name="question" type="string" not-null="true"/>
        <property name="answer" type="string" not-null="true"/>
       
        <!-- One-to-One Mapping to UserInfo -->
        <one-to-one name="userInfo" class="com.cyproj.pm.db.UserInfo" cascade="all" />
        <!-- End of One-to-One Mapping -->

        <!-- One-to-One Mapping to UserInfo -->
        <one-to-one name="userAccessRight" class="com.cyproj.pm.db.UserAccessRight" cascade="all" />
        <!-- End of One-to-One Mapping -->
       
        <!-- Set and One-to-Many Mapping to Contacts -->
        <set name="contactList" inverse="true">
            <key column="userID"/>
            <one-to-many class="com.cyproj.pm.db.Contact" />
        </set>
        <!-- End of One-to-Many -->

        <!-- Set and One-to-Many Mapping to Cash -->
        <set name="cashList" inverse="true">
            <key column="userID"/>
            <one-to-many class="com.cyproj.pm.db.Cash"/>
        </set>
        <!-- End of One-to-Many -->

        <!-- Set and One-to-Many Mapping to Credit Card -->
        <set name="creditCardList" inverse="true">
            <key column="userID"/>
            <one-to-many class="com.cyproj.pm.db.CreditCard"/>
        </set>
        <!-- End of One-to-Many -->

    </class>
    <!-- End of User Class -->
</hibernate-mapping >



Finance HBM

Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="com.cyproj.pm.db">
    <!-- Finance Class -->
    <class name="Finance" table="finance" >
        <id name="id" type="int" unsaved-value="0" column="Finance_ID">
            <generator class="identity"/>
        </id>
        <property name="date" type="date"/>
        <property name="information" type="string"/>
        <property name="amount" type="double"/>

        <!-- Many-to-One Mapping User-->
        <many-to-one name="user" class="com.cyproj.pm.db.User" column="userID" foreign-key="FK_FN_USER"/>
        <!-- End of Many-to-One Mapping -->

        <!-- Joined-Subclass to Credit Card Finance-->
        <joined-subclass name="CreditCard" table="creditcard">
            <key column="Finance_ID" not-null="true"/>
            <property name="CreditCardNumber" type="integer"/>
            <property name="isBillSettled" type="boolean"/>
        </joined-subclass>
        <!-- End of Joined-Subclass -->

        <!-- Joined-Subclass to Cash Finance -->
        <joined-subclass name="Cash" table="cash">
            <key column="Finance_ID" not-null="true"/>
            <property name="isSaving" type="boolean"/>
        </joined-subclass>
        <!-- End of Joined-Subclass -->

       
    </class>
    <!-- End of Finance Class -->

</hibernate-mapping>




Code between sessionFactory.openSession() and session.close():

Code:
    public User getUserByUsername(String username){
       
        Session session = HibernateUtil.getHbmSession();
        Transaction txn = null;
        User user = null;
        try{
            txn = session.beginTransaction();
            Query query = session.createQuery("SELECT userObj FROM User AS userObj WHERE userObj.loginID LIKE '"+username+"'");
            Iterator it = query.iterate();
            user = (it.hasNext()) ? (User)it.next() : null;
            txn.commit();
        }catch(Exception e){
            if(txn != null)
                txn.rollback();
            log.error("Hibernate error (getUserByUsername) - " + e);
        }finally{
            HibernateUtil.closeHbmSession();
        }
       
        return user;
    }
   


Name and version of the database you are using: MYSQL


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 20, 2006 8:11 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
If there are no rows in the DB that would end up in the set, then Hibernate won't call setCashList. So to always have something in there, to avoid getCashList returning null, just initialize the variable in your POJO as Collections.emptySet() instead of null.


Top
 Profile  
 
 Post subject: new Set versus empty set..
PostPosted: Mon Feb 20, 2006 9:31 pm 
Regular
Regular

Joined: Wed Feb 15, 2006 9:09 pm
Posts: 76
The hibernate tutorials initialize the Set by just doing a new HashSet(), are there any problems by using Collections.EmptySet? What about with generics?

Thanks.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 20, 2006 9:46 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
The problem with using Collections.emptySet() is that it's immutable. If you want to be able to add things to it, you'll have to initialize it as a new HashSet(). This is probably the way to go.

Collectiions.emptySet() is generics-friendly. It's Collections.EMPTY_SET that's raw.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 20, 2006 10:26 pm 
Newbie

Joined: Mon Feb 20, 2006 8:19 am
Posts: 5
Thank for the reply

I am quite sure that there is at least 1 record to be return from the database for the cashList. As shown in the following code:

Code:
            Query query = session.createQuery("SELECT userObj FROM User AS userObj WHERE userObj.loginID LIKE '"+username+"'");
            Iterator it = query.iterate();
            user = (it.hasNext()) ? (User)it.next() : null;


Won't Hibernate return the cashList as a embedded set inside the user object? However in my case, this user object do contain a cashlist with it, but it is a null set? Any idea?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 20, 2006 10:36 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
tngcy wrote:
I am quite sure that there is at least 1 record to be return from the database for the cashList. As shown in the following code:
Code:
            Query query = session.createQuery("SELECT userObj FROM User AS userObj WHERE userObj.loginID LIKE '"+username+"'");
            Iterator it = query.iterate();
            user = (it.hasNext()) ? (User)it.next() : null;

Where does that show that there are any values in the cashList? All that query would show is if there's any Users with a matching username. You need a query more like this to guarantee that you're getting a user with something in their cashList:
Code:
select u from User u
join u.cashList c
where c.isSaving is not null


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 20, 2006 11:01 pm 
Newbie

Joined: Mon Feb 20, 2006 8:19 am
Posts: 5
So do you mean that if I do the following

Code:
Query query = session.createQuery("from User");


It will only return all users from the User table? And it will not implicitly return all the cashList for each user?

If that is the case, why would the one-to-one relationship work with just the following code:

Code:
Query query = session.createQuery("SELECT userObj FROM User AS userObj WHERE userObj.loginID LIKE '"+username+"'");


In my case, the value for one-to-one relationship return together with the user object, why?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 20, 2006 11:22 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
tngcy wrote:
So do you mean that if I do the following
Code:
Query query = session.createQuery("from User");

It will only return all users from the User table? And it will not implicitly return all the cashList for each user?

It will return the cashList too, of course. The point is, it won't return only users with a cashList. So you won't know if setCashList is ever being called. My query will return only Users with something in their cashList, which is useful for testing.

If you create a user with no cashList, or an empty cashList, then save the user, no rows will be added to the cash table. When that user is loaded again, setCashList() will not be called, because there are no Cash entities to put in the cashList. My query aims to prove that your code works by ensuring that youfind some users with cash in their cashList.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 21, 2006 2:00 am 
Newbie

Joined: Mon Feb 20, 2006 8:19 am
Posts: 5
I had tried your statement. But it still return null cashSet. I have been trying an error and the following code work.

Code:
            Query query = session.createQuery("SELECT userObj FROM User AS userObj WHERE userObj.loginID LIKE '"+username+"'");
            Iterator it = query.iterate();
            user = (it.hasNext()) ? (User)it.next() : null;
            Cash c = (Cash)user.getCashList().iterator().next();


With Cash c = (Cash)user.getCashList().iterator().next(), it seems that it force hibernate to get the cashlist. Do you have any idea why would this so?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 21, 2006 2:14 am 
Newbie

Joined: Sat Feb 18, 2006 5:30 am
Posts: 17
Hibernate loads cashList set lazily by default. Field cashList in your User object should be initialized to lazy PersistentSet. When you call user.getCashList(), this set is fetched and initialized.

How do you know that your cashList field of User class contains null value?

Are you doing any bytecode instrumentation?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 21, 2006 2:15 am 
Newbie

Joined: Sat Feb 18, 2006 5:30 am
Posts: 17
What is the class of "user" variable? Could you perform .getClass() on it?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Feb 23, 2006 7:42 am 
Newbie

Joined: Mon Feb 20, 2006 8:19 am
Posts: 5
Sorry for late reply. I found cashList inside the user object is null through debugger. It will show the value of it. Anyway, I just realised that what you had said is true. By default, hibernate load set lazily. Unless I force it out with left join fetch keyword, it will not come out by default. Thank everyone for your timely help:)


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 12 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.