-->
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.  [ 16 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Nested Object Issue
PostPosted: Wed Mar 24, 2004 7:44 pm 
Senior
Senior

Joined: Wed Mar 24, 2004 11:40 am
Posts: 146
Location: Indianapolis, IN, USA
Hi All,

I am using Hibernate Version 2.1 with SAPDB 7.4.


The following is the Java code in question

Code:

public class User
{
  private Long userId = null;
  ...
  ...
  ...
  private User createBy = null;
  private User updateBy = null;

  public Long getUserId()
  {
    return this.userId();
  }
  public void setUserId(Long userId)
  {
    this.userId = userId
  }
  ...
  ...
  ...
  public User getCreateBy()
  {
    return this.createBy;
  }
  public void setCreateBy(User createBy)
  {
    this.createBy = createBy;
  } 
  public User getUpdateBy()
  {
    return this.updateBy;
  }
  public void setUpdateBy(User updateBy)
  {
    this.updateBy = updateBy;
  }
}


The following is the corresponding mapping from the XML Document.

Code:
  <?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>
    <class name="User" table="USERS" dynamic-update="false" dynamic-insert="false">

        <id name="userId" column="USERID" type="java.lang.Long">
            <generator class="sequence">
                <param name="userId">SEQ_USERID</param>
            </generator>
        </id>


        <many-to-one name="createBy" class="User" cascade="none"
            outer-join="false" update="false" insert="true"
            column="CREATEBY" not-null="true" unique="false"/>

        <many-to-one name="updateBy" class="User" cascade="none"
            outer-join="false" update="true" insert="true"
            column="UPDATEBY" not-null="true" unique="false"/>
    </class>

</hibernate-mapping>


I am able to retrieve the object successfully in my code doing the following.

Code:
  net.sf.hibernate.Session hibernateSession = HibernateManager.currentSession();
  Transaction tx = hibernateSession.beginTransaction();
  Criteria userCriteria = hibernateSession.createCriteria(User.class);
  userCriteria.add(Expression.eq("username", "gpani"));
  userCriteria.setMaxResults(1);
  ArrayList userList = (ArrayList) userCriteria.list();
  tx.commit();
  hibernateSession.close();
   
  if (userList != null)
  {
    user = (User) userList.get(0);
    logger.debug("UserId: " + user.getUserId());
    logger.debug("Created By: " + user.getCreateBy().getUserId());
    logger.debug("Updated By: " + user.getUpdateBy().getUserId());
  }
  HibernateManager.closeSession();


The thing that concerns me is that due to the nested nature of the User object in the form of createBy and updateBy within the User itself, I can do the following and get values.

Code:
  logger.debug("Updated By - Update By: " + user.getUpdateBy().getUpdateBy().getUserId());
  logger.debug("Updated By - Update By - Update By: " + user.getUpdateBy().getUpdateBy().getUpdateBy().getUserId());
  ...
  ...
  ...



While I have the createBy and updateBy objects in all my other objects to maintain an audit trail, the only one where it becomes an issue is the User object itself. I have considered the option of having the createBy and updateBy as the Long userId value for the User object only. But if there is any way to use my existing model I would like to stick to it.


When I execute the code it doesn't crash the system like you would expect it to should it go into an infinite loop. But at the same time, it seems like it is in an infinite loop. Has anyone else faced this sort of a problem and what kind of solution did you adopt?

Any help is appreciated.

TIA


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 25, 2004 6:21 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
No reason why it shouldn't work. Check the logs

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 25, 2004 6:25 pm 
Senior
Senior

Joined: Wed Mar 24, 2004 11:40 am
Posts: 146
Location: Indianapolis, IN, USA
emmanuel wrote:
No reason why it shouldn't work. Check the logs



Actually it worked. I was asking if this could cause any performance issues. I am just being cautious.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 25, 2004 6:27 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
It will if the user cycle is huge. proxy user and it will be fine.

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 26, 2004 11:09 am 
Senior
Senior

Joined: Wed Mar 24, 2004 11:40 am
Posts: 146
Location: Indianapolis, IN, USA
emmanuel wrote:
It will if the user cycle is huge. proxy user and it will be fine.



Thanks for the feedback. I was worried about that because the number of Users could be as high as 10,000.


My Hibernate fundamentals are still fairly weak, so maybe this question would sound stupid.

The relationship I have between the User and the createBy and updateBy entities is a many-to-one. When you suggested proxying , I am assuming that you meant set lazy to true. However, I can't see any way to turn lazy on for anything other than lists, sets etc. Is there any way to turn on lazy for a many-to-one relationship?


I am using XDoclet to generated my mapping files.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 26, 2004 11:11 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
The "target" class of your association should be lazy, A many-to-one B, make <class name="B" lazy="true"> and have a package-visible no-arg constructor for B, so CGLIB can generate a proxy.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 26, 2004 11:17 am 
Senior
Senior

Joined: Wed Mar 24, 2004 11:40 am
Posts: 146
Location: Indianapolis, IN, USA
christian wrote:
The "target" class of your association should be lazy, A many-to-one B, make <class name="B" lazy="true"> and have a package-visible no-arg constructor for B, so CGLIB can generate a proxy.



The problem here is that the target class is the original class itself.

The User object is created by another User. Hence, it is a A many-to-one A actually. That is my predicament.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 26, 2004 11:18 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Whats the problem? Make User lazy.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 26, 2004 11:38 am 
Senior
Senior

Joined: Wed Mar 24, 2004 11:40 am
Posts: 146
Location: Indianapolis, IN, USA
christian wrote:
Whats the problem? Make User lazy.



Thanks for your help. I still don't have a strong enough grasp of Hibernate as I am only 1 week into it. I have the following mapping for my class now.


Code:
<class
        name="com.foo.bar.beans.user.User"
        table="USERS"
        proxy="com.foo.bar.beans.user.User"
        dynamic-update="false"
        dynamic-insert="false"
        mutable="true"
    >



Is that the correct solution?

TIA


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 26, 2004 12:10 pm 
Senior
Senior

Joined: Wed Mar 24, 2004 11:40 am
Posts: 146
Location: Indianapolis, IN, USA
I have the following mapping in place.

Code:
<class
        name="com.foo.bar.beans.user.User"
        table="USERS"
        proxy="com.foo.bar.beans.user.User"
        dynamic-update="false"
        dynamic-insert="false"
        mutable="true"
    >



The following is a test sample of my code.

Code:
  net.sf.hibernate.Session hibernateSession = HibernateManager.currentSession();
  Transaction tx = hibernateSession.beginTransaction();
  Criteria userCriteria = hibernateSession.createCriteria(User.class);
  userCriteria.add(Expression.eq("username", "gpani"));
  userCriteria.setMaxResults(1);
  ArrayList userList = (ArrayList) userCriteria.list();
     
  if (userList != null)
  {
    user = (User) userList.get(0);
    out.println("Name: " + user.getFirstName() + " " + user.getLastName() + "<br>");
    out.println("UserGroup: " + user.getUserGroup().getUserGroupName() + "<br>");
    out.println("Created By: " + user.getCreateBy().getUsername() + "<br>");
    out.println("Updated By: " + user.getUpdateBy().getUsername() + "<br>");
  }
 
  tx.commit();
  hibernateSession.close();
  HibernateManager.closeSession();

  User foo = user.getUpdateBy().getCreateBy();
  out.println("Foo Username: " + foo.getUsername());


From my understanding of lazy, data is only populated if it is requested. So the User object named foo shouldn't have any results because I called it after closing my session. Yet, it seems to give me back valid data.

Am I missing the point or is there something that I am specifically doing wrong here?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 26, 2004 3:08 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
unless this instance has already been loaded (example by user.getCreateBy().getUsername())

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 26, 2004 3:14 pm 
Senior
Senior

Joined: Wed Mar 24, 2004 11:40 am
Posts: 146
Location: Indianapolis, IN, USA
emmanuel wrote:
unless this instance has already been loaded (example by user.getCreateBy().getUsername())



I must be doing something wrong because what you say makes sense. Yet I get values back for the following even after I close the session.

Code:

  net.sf.hibernate.Session hibernateSession = HibernateManager.currentSession();
  Transaction tx = hibernateSession.beginTransaction();
  Criteria userCriteria = hibernateSession.createCriteria(User.class);
  userCriteria.add(Expression.eq("username", "gpani"));
  userCriteria.setMaxResults(1);
  ArrayList userList = (ArrayList) userCriteria.list();
     
  if (userList != null)
  {
    user = (User) userList.get(0);
    out.println("Name: " + user.getFirstName() + " " + user.getLastName() + "<br>");
    out.println("UserGroup: " + user.getUserGroup().getUserGroupName() + "<br>");
    out.println("Created By: " + user.getCreateBy().getUsername() + "<br>");
    out.println("Updated By: " + user.getUpdateBy().getUsername() + "<br>");
  }
 
  tx.commit();
  // session closed
  hibernateSession.close();
  // manager closed
  HibernateManager.closeSession();


  User foo = user.getUpdateBy().getCreateBy();
  out.println("Foo Username: " + foo.getUsername());
  User bar = foo.getCreateBy().getUpdateBy();
  out.println("Bar Username: " + bar.getUsername());



Am I doing something wrong in setting the proxy?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 26, 2004 3:18 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Check the logs, you'll see if the objects are loaded for real.
It appears to be fine

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 26, 2004 3:45 pm 
Senior
Senior

Joined: Wed Mar 24, 2004 11:40 am
Posts: 146
Location: Indianapolis, IN, USA
emmanuel wrote:
Check the logs, you'll see if the objects are loaded for real.
It appears to be fine



It appears that the code executed two queries, one to populate the User and the other to get the UserGroup. That does make me feel more comfortable with my model.

However, I don't see a separate query to populate the createBy and updateBy entities. Shouldn't there be separate queries for the population of the createBy and updateBy objects?


Code:
Hibernate: select this.USERID as USERID0_, this.FIRSTNAME as FIRSTNAME0_, this.LASTNAME as LASTNAME0_, this.USERNAME as USERNAME0_, this.PASSWORD as PASSWORD0_, this.EMAIL as EMAIL0_, this.SUPERVISOREMAIL as SUPERVIS7_0_, this.USERGROUPID as USERGROU8_0_, this.NUMBEROFLOGINS as NUMBEROF9_0_, this.LASTLOGIN as LASTLOGIN0_, this.NUMBEROFORDERS as NUMBERO11_0_, this.LASTORDER as LASTORDER0_, this.ACCOUNTSTATUS as ACCOUNT13_0_, this.CREATEBY as CREATEBY0_, this.CREATEON as CREATEON0_, this.UPDATEBY as UPDATEBY0_, this.UPDATEON as UPDATEON0_ from USERS this where this.USERNAME=?

Hibernate: select usergroup0_.USERGROUPID as USERGROU1_0_, usergroup0_.USERGROUPNAME as USERGROU2_0_, usergroup0_.USERGROUPDESCRIPTION as USERGROU3_0_, usergroup0_.SHOWCART as SHOWCART0_, usergroup0_.CREATEON as CREATEON0_, usergroup0_.UPDATEON as UPDATEON0_ from USERGROUPS usergroup0_ where usergroup0_.USERGROUPID=?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 26, 2004 3:48 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
yes, so the lazy works.

_________________
Emmanuel


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