-->
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.  [ 2 posts ] 
Author Message
 Post subject: Many-to-one not mapping with subclasses
PostPosted: Thu Jul 27, 2006 9:41 am 
Newbie

Joined: Fri Jun 09, 2006 4:27 pm
Posts: 10
Hibernate 3.2 rc2
Spring 2.0 rc2
Oracle 9i
Java 5

I need another pair of eyes looking at this because I can't see the problem. In a nutshell my problem has to do with my many-to-one mapping not loading when a value is present, even if I attempt to force a load by setting lazy to false. There are no errors produced when running the code just a null value where there should be a proxy or the related object. I have tried this code using 3.1.2, 3.1.3, and the current 3.2 rc2 with the same results.

I have a parent/child relationship were the child is mapped using single table per hierarchy pattern. The parent is ChangeRequest and the abstract child is ChangeAction. ChangeAction has two subclasses PayChangeAction and JobChangeAction.

Here are the relevant parts of the ChangeRequest mapping:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping schema="PAF">

   <class
      name="paf.change.domain.ChangeRequest"
      table="CHANGE_REQUESTS">
      
      <id
         name="id"
         column="CHANGE_REQUEST_ID"
         type="long" />
         
      <!-- snip -->
      
      <set
         name="actions"
         cascade="all">
         <key
            column="CHANGE_REQUEST_ID"
            not-null="true"/>
         <one-to-many class="paf.change.domain.ChangeAction"/>
      </set>

      <!-- snip -->

   </class>

</hibernate-mapping>


Here are the relevant parts of the ChangeAction mapping:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping schema="PAF">

   <class
      name="paf.change.domain.ChangeAction"
      table="CHANGE_ACTIONS"
      abstract="true">
      
      <id
         name="id"
         column="CHANGE_ACTION_ID"
         type="long" />
         
      <discriminator
         column="TYPE_CD"
         type="string"/>

      <!-- snip -->

      <subclass
         name="paf.change.domain.JobChangeAction"
         discriminator-value="JOB">

         <property
            name="effectiveOn"
            column="EFFECTIVE_DT"
            type="zion.core.dao.hibernate.usertype.DateUserType" />

         <many-to-one
            name="jobChangeReason"
            class="hr.employee.domain.ActionReason"
            unique="true">
            <column name="JOB_CHANGE_ACTION_ID" sql-type="VARCHAR"/>
            <column name="JOB_CHANGE_REASON_ID" sql-type="VARCHAR"/>
         </many-to-one>

         <many-to-one
            name="job"
            class="hr.employee.domain.Job"
            unique="true">
            <column name="JOB_ID" sql-type="VARCHAR"/>
            <column name="JOB_SET_ID" sql-type="VARCHAR"/>
         </many-to-one>

      </subclass>

      <subclass
         name="paf.change.domain.PayChangeAction"
         discriminator-value="PAY">

         <property
            name="effectiveOn"
            column="EFFECTIVE_DT"
            type="zion.core.dao.hibernate.usertype.DateUserType" />

         <!-- snip -->

         <property
            name="payChangeAmount1"
            column="PAY_CHANGE_AMT1"
            type="zion.core.dao.hibernate.usertype.MoneyUserType" />

         <many-to-one
            name="payChangeReason1" 
            class="hr.employee.domain.ActionReason"
            unique="true">
            <column name="PAY_CHANGE_ACTION_ID1" sql-type="VARCHAR"/>
            <column name="PAY_CHANGE_REASON_ID1" sql-type="VARCHAR"/>
         </many-to-one>

         <!-- snip -->

      </subclass>

   </class>

</hibernate-mapping>


I use the following code in my ChangeRequestDAO implementation to load a ChangeRequest:
Code:
   public ChangeRequest read(Long id) {
      return (ChangeRequest) getHibernateTemplate().get(ChangeRequest.class, id);
   }


I also created a ChangeActionDAO implementation to load ChangeActions (I don't actually need this DAO since hibernate will take care of the associations for me but I have it for testing purposes and whatever lies down the road):
Code:
   public ChangeAction read(Long id) {
      return (ChangeAction) getHibernateTemplate().get(ChangeAction.class, id);
   }


Here are the relevant parts of the log (debug) when reading a PayChangeAction:
Code:
08:29:19,248 DEBUG SessionImpl:222 - opened session at timestamp: 4726812504633344
08:29:19,264 DEBUG JDBCTransaction:54 - begin
08:29:19,264 DEBUG ConnectionManager:415 - opening JDBC connection
08:29:19,279 DEBUG JDBCTransaction:59 - current autocommit status: true
08:29:19,279 DEBUG JDBCTransaction:62 - disabling autocommit
08:29:19,826 DEBUG Loader:1777 - loading entity: [paf.change.domain.ChangeAction#100001]
08:29:19,842 DEBUG AbstractBatcher:358 - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
08:29:19,842 DEBUG SQL:393 -
    select
        changeacti0_.CHANGE_ACTION_ID as CHANGE1_2_0_,
        changeacti0_.UPDATE_TS as UPDATE3_2_0_,
        changeacti0_.UPDATE_NAME as UPDATE4_2_0_,
        changeacti0_.VERSION as VERSION2_0_,
        changeacti0_.EFFECTIVE_DT as EFFECTIVE6_2_0_,
        changeacti0_.JOB_CHANGE_ACTION_ID as JOB7_2_0_,
        changeacti0_.JOB_CHANGE_REASON_ID as JOB8_2_0_,
        changeacti0_.JOB_ID as JOB9_2_0_,
        changeacti0_.JOB_SET_ID as JOB10_2_0_,
        changeacti0_.NEW_ANNUAL_PAY as NEW11_2_0_,
        changeacti0_.NEW_HOURLY_PAY as NEW12_2_0_,
        changeacti0_.NEXT_PAY_CHANGE_DT as NEXT13_2_0_,
        changeacti0_.PAY_CHANGE_AMT1 as PAY14_2_0_,
        changeacti0_.PAY_CHANGE_AMT2 as PAY15_2_0_,
        changeacti0_.PAY_CHANGE_AMT3 as PAY16_2_0_,
        changeacti0_.PAY_CHANGE_ACTION_ID1 as PAY17_2_0_,
        changeacti0_.PAY_CHANGE_REASON_ID1 as PAY18_2_0_,
        changeacti0_.PAY_CHANGE_ACTION_ID2 as PAY19_2_0_,
        changeacti0_.PAY_CHANGE_REASON_ID2 as PAY20_2_0_,
        changeacti0_.PAY_CHANGE_ACTION_ID3 as PAY21_2_0_,
        changeacti0_.PAY_CHANGE_REASON_ID3 as PAY22_2_0_,
        changeacti0_.TYPE_CD as TYPE2_2_0_
    from
        PAF.CHANGE_ACTIONS changeacti0_
    where
        changeacti0_.CHANGE_ACTION_ID=?
Hibernate:
    select
        changeacti0_.CHANGE_ACTION_ID as CHANGE1_2_0_,
        changeacti0_.UPDATE_TS as UPDATE3_2_0_,
        changeacti0_.UPDATE_NAME as UPDATE4_2_0_,
        changeacti0_.VERSION as VERSION2_0_,
        changeacti0_.EFFECTIVE_DT as EFFECTIVE6_2_0_,
        changeacti0_.JOB_CHANGE_ACTION_ID as JOB7_2_0_,
        changeacti0_.JOB_CHANGE_REASON_ID as JOB8_2_0_,
        changeacti0_.JOB_ID as JOB9_2_0_,
        changeacti0_.JOB_SET_ID as JOB10_2_0_,
        changeacti0_.NEW_ANNUAL_PAY as NEW11_2_0_,
        changeacti0_.NEW_HOURLY_PAY as NEW12_2_0_,
        changeacti0_.NEXT_PAY_CHANGE_DT as NEXT13_2_0_,
        changeacti0_.PAY_CHANGE_AMT1 as PAY14_2_0_,
        changeacti0_.PAY_CHANGE_AMT2 as PAY15_2_0_,
        changeacti0_.PAY_CHANGE_AMT3 as PAY16_2_0_,
        changeacti0_.PAY_CHANGE_ACTION_ID1 as PAY17_2_0_,
        changeacti0_.PAY_CHANGE_REASON_ID1 as PAY18_2_0_,
        changeacti0_.PAY_CHANGE_ACTION_ID2 as PAY19_2_0_,
        changeacti0_.PAY_CHANGE_REASON_ID2 as PAY20_2_0_,
        changeacti0_.PAY_CHANGE_ACTION_ID3 as PAY21_2_0_,
        changeacti0_.PAY_CHANGE_REASON_ID3 as PAY22_2_0_,
        changeacti0_.TYPE_CD as TYPE2_2_0_
    from
        PAF.CHANGE_ACTIONS changeacti0_
    where
        changeacti0_.CHANGE_ACTION_ID=?
08:29:19,857 DEBUG AbstractBatcher:374 - about to open ResultSet (open ResultSets: 0, globally: 0)
08:29:19,857 DEBUG Loader:1164 - result row: EntityKey[paf.change.domain.ChangeAction#100001]
08:29:19,888 DEBUG AbstractBatcher:381 - about to close ResultSet (open ResultSets: 1, globally: 1)
08:29:19,904 DEBUG AbstractBatcher:366 - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
08:29:19,904 DEBUG TwoPhaseLoad:107 - resolving associations for [paf.change.domain.PayChangeAction#100001]
08:29:19,951 DEBUG TwoPhaseLoad:206 - done materializing entity [paf.change.domain.PayChangeAction#100001]
08:29:19,951 DEBUG StatefulPersistenceContext:748 - initializing non-lazy collections
08:29:19,951 DEBUG Loader:1808 - done entity load
08:29:19,951 DEBUG SessionImpl:825 - initializing proxy: [hr.employee.domain.ActionReason#component[actionId,reasonId]{actionId=PAY, reasonId=MER}]
08:29:19,967 DEBUG Loader:1777 - loading entity: [hr.employee.domain.ActionReason#component[actionId,reasonId]{actionId=PAY, reasonId=MER}]
08:29:19,967 DEBUG AbstractBatcher:358 - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
08:29:19,967 DEBUG SQL:393 -
    select
        actionreas0_.ACTION as ACTION16_0_,
        actionreas0_.REASON as REASON16_0_,
        actionreas0_.DESCR as DESCR16_0_,
        actionreas0_.AVAILABLE as AVAILABLE16_0_,
        actionreas0_.UPDATE_TS as UPDATE5_16_0_
    from
        PSFT_DATAMART.PSFT_REASON actionreas0_
    where
        actionreas0_.ACTION=?
        and actionreas0_.REASON=?
Hibernate:
    select
        actionreas0_.ACTION as ACTION16_0_,
        actionreas0_.REASON as REASON16_0_,
        actionreas0_.DESCR as DESCR16_0_,
        actionreas0_.AVAILABLE as AVAILABLE16_0_,
        actionreas0_.UPDATE_TS as UPDATE5_16_0_
    from
        PSFT_DATAMART.PSFT_REASON actionreas0_
    where
        actionreas0_.ACTION=?
        and actionreas0_.REASON=?
08:29:19,967 DEBUG AbstractBatcher:374 - about to open ResultSet (open ResultSets: 0, globally: 0)
08:29:19,967 DEBUG Loader:1164 - result row: EntityKey[hr.employee.domain.ActionReason#component[actionId,reasonId]{actionId=PAY, reasonId=MER}]
08:29:19,967 DEBUG AbstractBatcher:381 - about to close ResultSet (open ResultSets: 1, globally: 1)
08:29:19,967 DEBUG AbstractBatcher:366 - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
08:29:19,967 DEBUG TwoPhaseLoad:107 - resolving associations for [hr.employee.domain.ActionReason#component[actionId,reasonId]{actionId=PAY, reasonId=MER}]
08:29:19,967 DEBUG TwoPhaseLoad:206 - done materializing entity [hr.employee.domain.ActionReason#component[actionId,reasonId]{actionId=PAY, reasonId=MER}]
08:29:19,967 DEBUG StatefulPersistenceContext:748 - initializing non-lazy collections
08:29:19,967 DEBUG Loader:1808 - done entity load
08:29:19,967 DEBUG JDBCTransaction:152 - rollback
08:29:19,998 DEBUG JDBCTransaction:193 - re-enabling autocommit
08:29:19,998 DEBUG JDBCTransaction:163 - rolled back JDBC Connection
08:29:19,998 DEBUG ConnectionManager:296 - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
08:29:19,998 DEBUG ConnectionManager:435 - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
08:29:19,998 DEBUG ConnectionManager:296 - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!


Here are the relevant parts of the log (debug) when reading a JobChangeAction:
Code:
08:29:19,998 DEBUG SessionImpl:222 - opened session at timestamp: 4726812508151808
08:29:19,998 DEBUG JDBCTransaction:54 - begin
08:29:19,998 DEBUG ConnectionManager:415 - opening JDBC connection
08:29:20,013 DEBUG JDBCTransaction:59 - current autocommit status: true
08:29:20,013 DEBUG JDBCTransaction:62 - disabling autocommit
08:29:20,326 DEBUG Loader:1777 - loading entity: [paf.change.domain.ChangeAction#100002]
08:29:20,326 DEBUG AbstractBatcher:358 - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
08:29:20,326 DEBUG SQL:393 -
    select
        changeacti0_.CHANGE_ACTION_ID as CHANGE1_2_0_,
        changeacti0_.UPDATE_TS as UPDATE3_2_0_,
        changeacti0_.UPDATE_NAME as UPDATE4_2_0_,
        changeacti0_.VERSION as VERSION2_0_,
        changeacti0_.EFFECTIVE_DT as EFFECTIVE6_2_0_,
        changeacti0_.JOB_CHANGE_ACTION_ID as JOB7_2_0_,
        changeacti0_.JOB_CHANGE_REASON_ID as JOB8_2_0_,
        changeacti0_.JOB_ID as JOB9_2_0_,
        changeacti0_.JOB_SET_ID as JOB10_2_0_,
        changeacti0_.NEW_ANNUAL_PAY as NEW11_2_0_,
        changeacti0_.NEW_HOURLY_PAY as NEW12_2_0_,
        changeacti0_.NEXT_PAY_CHANGE_DT as NEXT13_2_0_,
        changeacti0_.PAY_CHANGE_AMT1 as PAY14_2_0_,
        changeacti0_.PAY_CHANGE_AMT2 as PAY15_2_0_,
        changeacti0_.PAY_CHANGE_AMT3 as PAY16_2_0_,
        changeacti0_.PAY_CHANGE_ACTION_ID1 as PAY17_2_0_,
        changeacti0_.PAY_CHANGE_REASON_ID1 as PAY18_2_0_,
        changeacti0_.PAY_CHANGE_ACTION_ID2 as PAY19_2_0_,
        changeacti0_.PAY_CHANGE_REASON_ID2 as PAY20_2_0_,
        changeacti0_.PAY_CHANGE_ACTION_ID3 as PAY21_2_0_,
        changeacti0_.PAY_CHANGE_REASON_ID3 as PAY22_2_0_,
        changeacti0_.TYPE_CD as TYPE2_2_0_
    from
        PAF.CHANGE_ACTIONS changeacti0_
    where
        changeacti0_.CHANGE_ACTION_ID=?
Hibernate:
    select
        changeacti0_.CHANGE_ACTION_ID as CHANGE1_2_0_,
        changeacti0_.UPDATE_TS as UPDATE3_2_0_,
        changeacti0_.UPDATE_NAME as UPDATE4_2_0_,
        changeacti0_.VERSION as VERSION2_0_,
        changeacti0_.EFFECTIVE_DT as EFFECTIVE6_2_0_,
        changeacti0_.JOB_CHANGE_ACTION_ID as JOB7_2_0_,
        changeacti0_.JOB_CHANGE_REASON_ID as JOB8_2_0_,
        changeacti0_.JOB_ID as JOB9_2_0_,
        changeacti0_.JOB_SET_ID as JOB10_2_0_,
        changeacti0_.NEW_ANNUAL_PAY as NEW11_2_0_,
        changeacti0_.NEW_HOURLY_PAY as NEW12_2_0_,
        changeacti0_.NEXT_PAY_CHANGE_DT as NEXT13_2_0_,
        changeacti0_.PAY_CHANGE_AMT1 as PAY14_2_0_,
        changeacti0_.PAY_CHANGE_AMT2 as PAY15_2_0_,
        changeacti0_.PAY_CHANGE_AMT3 as PAY16_2_0_,
        changeacti0_.PAY_CHANGE_ACTION_ID1 as PAY17_2_0_,
        changeacti0_.PAY_CHANGE_REASON_ID1 as PAY18_2_0_,
        changeacti0_.PAY_CHANGE_ACTION_ID2 as PAY19_2_0_,
        changeacti0_.PAY_CHANGE_REASON_ID2 as PAY20_2_0_,
        changeacti0_.PAY_CHANGE_ACTION_ID3 as PAY21_2_0_,
        changeacti0_.PAY_CHANGE_REASON_ID3 as PAY22_2_0_,
        changeacti0_.TYPE_CD as TYPE2_2_0_
    from
        PAF.CHANGE_ACTIONS changeacti0_
    where
        changeacti0_.CHANGE_ACTION_ID=?
08:29:20,326 DEBUG AbstractBatcher:374 - about to open ResultSet (open ResultSets: 0, globally: 0)
08:29:20,326 DEBUG Loader:1164 - result row: EntityKey[paf.change.domain.ChangeAction#100002]
08:29:20,326 DEBUG AbstractBatcher:381 - about to close ResultSet (open ResultSets: 1, globally: 1)
08:29:20,326 DEBUG AbstractBatcher:366 - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
08:29:20,341 DEBUG TwoPhaseLoad:107 - resolving associations for [paf.change.domain.JobChangeAction#100002]
08:29:20,341 DEBUG TwoPhaseLoad:206 - done materializing entity [paf.change.domain.JobChangeAction#100002]
08:29:20,341 DEBUG StatefulPersistenceContext:748 - initializing non-lazy collections
08:29:20,341 DEBUG Loader:1808 - done entity load
08:29:20,341 DEBUG JDBCTransaction:152 - rollback
08:29:20,357 DEBUG JDBCTransaction:193 - re-enabling autocommit
08:29:20,357 DEBUG JDBCTransaction:163 - rolled back JDBC Connection
08:29:20,357 DEBUG ConnectionManager:296 - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
08:29:20,357 DEBUG ConnectionManager:435 - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
08:29:20,357 DEBUG ConnectionManager:296 - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!


When I run my unit test I use DBUnit to initialize the database to a known state and then attempt to read a ChangeAction by ID. If I read a PayChangeAction I find that the many-to-one assocation with ActionReason (payChangeReason1) loads as expected, and that expectation is a proxy.

However when I attempt to read a JobChangeAction I find that the many-to-one assocation with ActionReason (jobChangeReason) is always null and the many-to-one assocation with Job (job) is always null despite the fact that there are values in the tables and that the ChangeAction record correctly relates to those records. The fact that the Job association does not work is one thing but the fact that the ActionReason association works in one subclass and not the other is rather strange.

I have searched the forums and found some people that have had a similar problem as far back as version 2.x but there never seemed to be solution posted, or at least a solution that worked for me. Even tenwit posted the same problem but he was able to get around it by setting fetch to "join" rather than to "select". I would give this a try but it is not a feasible solution because my subclasses have more than one many-to-one associations. JobChangeAction has two, PayChangeAction actually has three, and there are several other ChangeAction subclasses on the way, one of which has seven assocations.

Has anybody encountered this problem before? Is there something obvious that I am missing? What additional information could I provide that would be helpful in solving this problem?

I am hoping that my long history of finding solutions to my problems right after I post the question will work yet again.

*crosses fingers*


Top
 Profile  
 
 Post subject: Re: Many-to-one not mapping with subclasses
PostPosted: Fri Jul 28, 2006 12:34 pm 
Newbie

Joined: Fri Jun 09, 2006 4:27 pm
Posts: 10
I discovered the source of the problem but not the specific cause. In my spring test case I used DBUnit to load data into the database to initialize it to a known state. There seems to be a problem between this activity and Hibernate. Hibernate was not correctly recognizing the database changes and could not find what it was looking for in the database and was returning null rather than a proxy or an entity.

I did some research at the DBUnit site but did not find anything of great interest.

I then did some research at the spring site and found many people tyring to do the same thing and having problems with various related things but nothing that duplicated my problem exactly. In general it seemed that I need to flush Hibernate after making database changes. I tried doing this after making the database changes in my setup but that did not make any difference.

Is anybody here using spring and DBUnit for integration testing? If so are you flushing the hibernate session? When? How?

I am thinking of ditching DBUnit and relying on the provided spring testing features. Of course I need to try out this particular case using spring alone to determine if I still have the same problem.


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