-->
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.  [ 10 posts ] 
Author Message
 Post subject: table per class hierarcy: wrong class retrieve
PostPosted: Thu Mar 11, 2010 3:55 am 
Newbie

Joined: Wed Mar 03, 2010 8:27 pm
Posts: 9
Location: Russia, Perm
Hi!

I've got mapping like this

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>
  <class discriminator-value="0" name="core.applications.ets.questions.Question" table="questions" abstract="true">
    <id column="id" name="id" type="integer">
      <generator class="increment"/>
    </id>
    <discriminator column="type_id" type="integer"/>
    <many-to-one class="core.applications.ets.questions.Question" column="original_question_id" name="originalQuestion"/>
    <many-to-one class="core.applications.ets.questions.Topic" column="topic_id" name="topic"/>
    <property column="text" name="text" type="string"/>
    <property column="create_date" name="createDate" type="date"/>
    <property column="is_archive" name="archive" type="boolean"/>
    <property column="difficulty" name="difficulty" type="double"/>
    <subclass discriminator-value="1" name="core.applications.ets.questions.manytomany.ManyToManyQuestion" >
      <set cascade="all" lazy="true" name="options" order-by="id">
        <key column="question_id"/>
        <one-to-many class="core.applications.ets.questions.manytomany.ManyToManyOption"/>
      </set>
    </subclass>
  </class>
</hibernate-mapping>

<?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>
  <class name="core.applications.ets.TestQuestion" table="test_questions">
    <id column="id" name="id" type="integer">
      <generator class="increment"/>
    </id>
    <many-to-one class="core.applications.ets.questions.Question" column="question_id" name="question"/>
    <many-to-one class="core.applications.ets.TestTopic" column="test_topic_id" name="testTopic"/>
  </class>
</hibernate-mapping>


and 5 rows in table "questions", all rows has type_id = 1

when i execute following code
Code:
            TestQuestion q = TestQuestionDAO.getById(1);
            //ManyToManyQuestion qm = (ManyToManyQuestion) q.getQuestion();
            out.print(q.getQuestion());
            out.print(q.getQuestion() instanceof ManyToManyQuestion);

I get
Code:
core.applications.ets.questions.manytomany.ManyToManyQuestion@1237c9b
false

and if I try to uncomment second line:
Code:
java.lang.ClassCastException: core.applications.ets.questions.Question_$$_javassist_11 cannot be cast to core.applications.ets.questions.manytomany.ManyToManyQuestion
   core.applications.ets.test.TestServlet.doAction(TestServlet.java:43)
   core.CoreActionServlet.processRequest(CoreActionServlet.java:34)
   core.CoreActionServlet.doGet(CoreActionServlet.java:59)
   javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
   javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
   core.CoreRequestDispatcher.include(CoreRequestDispatcher.java:90)
   core.CoreRequestDispatcher.include(CoreRequestDispatcher.java:63)
   core.os.CoreFile.doExecute(CoreFile.java:71)
   core.os.CoreFile.action(CoreFile.java:189)
   core.os.CoreDirectory.action(CoreDirectory.java:95)
   core.os.CoreAbstractFile.process(CoreAbstractFile.java:597)
   core.os.CoreFileSystem.process(CoreFileSystem.java:359)
   core.os.CoreOperatingSystem.process(CoreOperatingSystem.java:137)
   core.CoreControllerServlet.doAction(CoreControllerServlet.java:371)
   core.applications.ets.test.ControllerServlet.doAction(ControllerServlet.java:23)
   core.CoreControllerServlet.doGet(CoreControllerServlet.java:435)
   javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
   javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
   org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:390)


why q.getQuestion() is not an instance of core.applications.ets.questions.manytomany.ManyToManyQuestion?


Top
 Profile  
 
 Post subject: Re: table per class hierarcy: wrong class retrieve
PostPosted: Thu Mar 11, 2010 4:21 am 
Expert
Expert

Joined: Tue Jun 16, 2009 3:36 am
Posts: 990
Quote:
why q.getQuestion() is not an instance of core.applications.ets.questions.manytomany.ManyToManyQuestion?


This is because of how Hibernate does implement lazy loading with proxies.
Unfortunately hibernate proxies are not completely transparent to the user if there are involved class hierarchy.
Question_$$_javassist_11 is a proxy object which type is a runtime generated subclass of Question
and therefore it cannot be cast to ManyToManyQuestion.
This problem is well known.


Before you call the instanceof operator you must explicitely 'deproxy' your lazy object.

Code:
TestQuestion q = TestQuestionDAO.getById(1);
Question q1 = (Question) q.getQuestion();
ManyToManyQuestion qm = null;
if (q1 instanceof HibernateProxy)
            qm = (ManyToManyQuestion )  ((HibernateProxy) q1).getHibernateLazyInitializer().getImplementation();
else
     qm = (ManyToManyQuestion ) q1; 


The other solution is to declare the relation EAGER instead to LAZY, so you don't have the proxi at all.


Top
 Profile  
 
 Post subject: Re: table per class hierarcy: wrong class retrieve
PostPosted: Thu Mar 11, 2010 4:22 am 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
It has do with proxies not knowing which actual instance to use until the entity is initialized. It is expected behavior and is explained here: http://docs.jboss.org/hibernate/stable/ ... ng-proxies


Top
 Profile  
 
 Post subject: Re: table per class hierarcy: wrong class retrieve
PostPosted: Thu Mar 11, 2010 5:27 am 
Newbie

Joined: Wed Mar 03, 2010 8:27 pm
Posts: 9
Location: Russia, Perm
Thanks, fetch="join" is the solution for me!


Top
 Profile  
 
 Post subject: Re: table per class hierarcy: wrong class retrieve
PostPosted: Mon Mar 15, 2010 1:06 am 
Newbie

Joined: Wed Mar 03, 2010 8:27 pm
Posts: 9
Location: Russia, Perm
Want to ask one more question.
My previous problem was solved by using fetch="join" in many-to-one tag. Mappings are:
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>
  <class name="core.applications.ets.Attempt" table="attempts">
    <id column="id" name="id" type="integer">
      <generator class="increment"/>
    </id>
    <many-to-one fetch="join" lazy="no-proxy" class="core.applications.ets.Variant" column="variant_id" name="variant"/>
    <many-to-one class="core.applications.ets.Testee" column="testee_id" name="testee"/>
    <many-to-one class="core.applications.ets.Assignment" column="assignment_id" name="assignment"/>
    <property column="time_start" name="timeStart" type="timestamp"/>
    <property column="time_end" name="timeEnd" type="timestamp"/>
    <property column="value" name="value" type="double"/>
    <property column="client_hash" name="clientHash" type="string"/>
    <set cascade="all" lazy="true" name="attemptTopics" order-by="id">
      <key column="attempt_id"/>
      <one-to-many class="core.applications.ets.AttemptTopic"/>
    </set>
  </class>
</hibernate-mapping>

<?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>
  <class name="core.applications.ets.Variant" table="variants">
    <id column="id" name="id" type="integer">
      <generator class="increment"/>
    </id>
    <property column="name" name="name" type="string"/>
    <many-to-one cascade="all" class="core.applications.ets.QuestionSelector" column="question_selector_id" name="questionSelector"/>
    <many-to-one cascade="all" class="core.applications.ets.VariantSelector" column="variant_selector_id" name="variantSelector"/>
    <many-to-one fetch="join" lazy="no-proxy" class="core.applications.ets.Test" column="test_id" name="test"/>
    <set cascade="all" lazy="true" name="variantTopics" order-by="id">
      <key column="variant_id"/>
      <one-to-many class="core.applications.ets.VariantTopic"/>
    </set>
  </class>
</hibernate-mapping>

<?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>
  <class name="core.applications.ets.Test" table="tests">
    <id column="id" name="id" type="integer">
      <generator class="increment"/>
    </id>
    <property column="name" name="name" type="string"/>
    <property column="create_date" name="createDate" type="date"/>
    <set cascade="all" lazy="true" name="assignments" order-by="id">
      <key column="test_id"/>
      <one-to-many class="core.applications.ets.Assignment"/>
    </set>
    <set cascade="all" lazy="true" name="testTopics" order-by="id">
      <key column="test_id"/>
      <one-to-many class="core.applications.ets.TestTopic"/>
    </set>
    <set cascade="all" lazy="true" name="variants" order-by="id">
      <key column="test_id"/>
      <one-to-many class="core.applications.ets.Variant"/>
    </set>
  </class>
</hibernate-mapping>

It means that relations between Attempt, Variant and Test are

Attempt *-1 Variant *-1 Test

When I trying to get an attempt hibernate generates that sql, and it's ok
Code:
Hibernate:
    select
        attempt0_.id as id1_2_,
        attempt0_.variant_id as variant2_1_2_,
        attempt0_.testee_id as testee3_1_2_,
        attempt0_.assignment_id as assignment4_1_2_,
        attempt0_.time_start as time5_1_2_,
        attempt0_.time_end as time6_1_2_,
        attempt0_.value as value1_2_,
        attempt0_.client_hash as client8_1_2_,
        variant1_.id as id12_0_,
        variant1_.name as name12_0_,
        variant1_.question_selector_id as question3_12_0_,
        variant1_.variant_selector_id as variant4_12_0_,
        variant1_.test_id as test5_12_0_,
        test2_.id as id8_1_,
        test2_.name as name8_1_,
        test2_.create_date as create3_8_1_
    from
        attempts attempt0_
    left outer join
        variants variant1_
            on attempt0_.variant_id=variant1_.id
    left outer join
        tests test2_
            on variant1_.test_id=test2_.id
    where
        attempt0_.id=?


But object Test is proxyfied anyway...

What should I do to make hibernate load it without proxy?

P.S. I have all these problems because google-gson works only with field access and not with getters/setters. If anyone could show me some tool for JSON serialization/desirialization which uses getters/setters and is as easy as gson I will be gratefull.

Thank you.


Top
 Profile  
 
 Post subject: Re: table per class hierarcy: wrong class retrieve
PostPosted: Mon Mar 15, 2010 3:16 am 
Expert
Expert

Joined: Tue Jun 16, 2009 3:36 am
Posts: 990
Quote:
But object Test is proxyfied anyway...


Can it be that you already loaded the concerning Test object into persistence context
before executing the query ? (i.e. with session.load(Test.class, id) or by navigation).
Remember that whether a determinate object is returned as proxy or not, depends on it's first access in persistent context.
Once a determinate object is loaded in persistent context as proxy, it will be returned even as proxy in query results of
non-lazy queries.


Top
 Profile  
 
 Post subject: Re: table per class hierarcy: wrong class retrieve
PostPosted: Mon Mar 15, 2010 4:24 am 
Newbie

Joined: Wed Mar 03, 2010 8:27 pm
Posts: 9
Location: Russia, Perm
I don't see any select from tests before that select from variants in output log, but this behaviour is not good for me anyway. Is there any way to make hibernate always load these objects without proxies?


Top
 Profile  
 
 Post subject: Re: table per class hierarcy: wrong class retrieve
PostPosted: Mon Mar 15, 2010 4:32 am 
Expert
Expert

Joined: Tue Jun 16, 2009 3:36 am
Posts: 990
Quote:
I don't see any select from tests before that select from variants in output log


A call similar to

Code:
session.load(Test.class, id)


would create a proxy without producing a database hit (= a select which you would see in the output-log).
It also could be that the test-object was loaded as proxy navigating it from a class different than variant?

Quote:
Is there any way to make hibernate always load these objects without proxies?


If you want avoid proxies completely then you must:
-never declare toOne-relations lazy
-never use session.load (or entityManager.getReference())


Top
 Profile  
 
 Post subject: Re: table per class hierarcy: wrong class retrieve
PostPosted: Mon Mar 15, 2010 5:27 am 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
Quote:
Is there any way to make hibernate always load these objects without proxies?


<class ... lazy="false" ...>


Top
 Profile  
 
 Post subject: Re: table per class hierarcy: wrong class retrieve
PostPosted: Mon Mar 15, 2010 7:10 am 
Newbie

Joined: Wed Mar 03, 2010 8:27 pm
Posts: 9
Location: Russia, Perm
Thanks for your help!

I think there is no way to connect hibernate lazy fetching and google-gson, unless you fetch all database at start... I'm very disappointed in gson.

Searching for new JSON serialization library.


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