-->
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: $$EnhancerByCGLIB$$
PostPosted: Thu Aug 31, 2006 9:03 am 
Newbie

Joined: Thu Aug 31, 2006 7:56 am
Posts: 14
I am using Hibernate-Version: 3.0.5 in eclipse3.2 to manage persistance in an application. However, when I use
Code:

    Query q = session.createQuery("from MyObject mo ");
   
    Iterator i = q.iterate();
    while (i.hasNext())
    {
     
      Object o = i.next();
      System.out.println(o.getClass().getName());
    }


I get strange results, namely:

com.myapp.MyObject$$EnhancerByCGLIB$$ae7285a7
com.myapp.MyObject
com.myapp.MyObject$$EnhancerByCGLIB$$ae7285a7
com.myapp.MyObject$$EnhancerByCGLIB$$ae7285a7

There are 4 records in the table, and the second one is retrieved properly, but the others are of type com.myapp.MyObject$$EnhancerByCGLIB$$ae7285a7 and nor com.myapp.MyObject.

Any suggestions?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Aug 31, 2006 9:44 am 
Newbie

Joined: Thu Aug 31, 2006 9:24 am
Posts: 1
I got the same thing today.

As far as I understood the reason is that this object acts as a value of the field which is lazy-initialized earlier in the same session (this can be OneToMany relation or ManyToOne with fetch set to FetchType.LAZY). The proxy (it looks like $$Enhancer) is created for this object, but it is never hit and therefore real object is not taken from the DB. Instead the proxy is stored in the 1st level cache.

And when you later (but still in the same session) try to load the object, Hibernate takes it from cache (thinking that this is a real object, but indeed it is a proxy)

If you don't need to print out the class name or to cast the object to the sub-class, you may use the proxy - it should still work well.

But if you need the object itself, try to evict it then to get it again.

In your case it will look like this:

Code:
    Query q = session.createQuery("from MyObject mo ");
   
    Iterator i = q.iterate();
    while (i.hasNext())
    {
     
      Object o = i.next();

      session.evict(o);
      o = session.get(MyObject.class, o.getId());

      System.out.println(o.getClass().getName());
    }


I don't know whether it is a bug or a designed behavior.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Aug 31, 2006 10:56 am 
Newbie

Joined: Thu Aug 31, 2006 7:56 am
Posts: 14
Thanks for the reply atoh, but I am still in difficulties. The code you suggest more or less makes sence to be, by the 'o.getId()' is invalid as o is an Object. I tried replacing it with '((MyClass)o).getId()' but I then got a an exception as follows:

org.hibernate.exception.JDBCConnectionException: could not load an entity: [com.myapp.MyClass#7]

I then changed the code (see below) to retriieve the id before the call to evict(), but still no joy, I get the same error as above. Did you get your example working???

I should mention that this is the first call on the session, i.e. no other records have been read or saved to the db in this session.

Code:
    Query q = session.createQuery("from MyObject mo ");
   
    Iterator i = q.iterate();
    while (i.hasNext())
    {
     
      Object o = i.next();
      int id = ((MyClass)o).getId();  // retrieved the id correctly!!!

      session.evict(o);
      o = session.get(MyObject.class, new Long(id));   <<<< Exception

      System.out.println(o.getClass().getName());
    }



The mapping file is as follows:

Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >

<hibernate-mapping package="com.myapp">
   <class
      name="MyClass"
      table="MyClass"
   >
      <meta attribute="sync-DAO">false</meta>
      <id
         name="Id"
         type="integer"
         column="id"
      >
         <generator class="increment"/>
      </id>

      <property
         name="Code"
         column="code"
         type="string"
         not-null="true"
         length="10"
      />
      <property
         name="Name"
         column="name"
         type="string"
         not-null="true"
         length="50"
      />
   </class>   
</hibernate-mapping>


Top
 Profile  
 
 Post subject:
PostPosted: Thu Aug 31, 2006 4:29 pm 
Senior
Senior

Joined: Tue Mar 09, 2004 2:38 pm
Posts: 141
Location: Lowell, MA USA
Hibernate behaves differently when using Query.list() and Query.iterate(). When you use Query.iterate(), Hibernate will issue a SQL query that will fetch only the IDs. When you iterate over the results, it will load the entity lazily. Query.iterate() is an optimization for the Level 2 cache. By loading only the IDs, it can quickly get the entity from the second level cache if its there, otherwise it hits the database. If you're not using a second level cache, Query.iterate() will be much slower than Query.list().

Now, when you execute your code:

Code:
    Query q = session.createQuery("from MyObject mo ");
   
    Iterator i = q.iterate();
    while (i.hasNext())
    {
     
      Object o = i.next();
      System.out.println(o.getClass().getName());
    }


The iteration only contains proxies to the orginal object. Because you did not access any properties on the object, the instance was not loaded, thus what you are seeing. If you changed your code to something like:

Code:
    Query q = session.createQuery("from MyObject mo ");
   
    Iterator i = q.iterate();
    while (i.hasNext())
    {
     
      Object o = i.next();
      o.getSomeProperty(); //-- this will trigger a DB load.
      System.out.println(o.getClass().getName()); //-- this will now print out the actual class name
    }


You'll see hibernate issue a SELECT for that ID and the class name should not be a proxy. If changed your code to user q.list().iterator(), you'd avoid the issue all together.

Lastly, if you want to get the actual class name of a proxy, you can do something like this:

Code:
if (object instanceof HibernateProxy){
         HibernateProxy proxy = (HibernateProxy) object;
         return proxy.getHibernateLazyInitializer().getImplementation();
      }


Hope this clears things up.

Ryan-

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

Please remember to rate!


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.