-->
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.  [ 5 posts ] 
Author Message
 Post subject: Extra queries with a one-to-many
PostPosted: Thu Apr 19, 2007 1:38 pm 
Newbie

Joined: Fri Mar 30, 2007 7:15 pm
Posts: 6
Versions:
Hibernate 3.2.2 ga
Database: Oracle 8.1.7
JDK: 1.5


I have two domain objects (one-to-many), BusinessRefence and BusinessReferenceValues that I want to load with one Criteria query (below). When I run the query, I get the correct set of BusinessReference domain objects. However, when I then attempt to load the BusinessReferenceValues (via businessRefence.getBusinessReferenceValues()), Hibernate generates extra queries to load the BusinessReferenceValue's (one query per BusinessReferenceValue) even though I have fetch="join" in the mapping. Using fetch="subselect" minimizes the number of extra queries, but why does Hibernate even need these extra queries? Shouldn't the first query provide enough information to hydrate both sides of the one-to-many.


CRITERIA QUERY:

Code:
Criteria query = getSession().createCriteria(BusinessReference.class);

query.createAlias("businessReferenceValues", "businessReferenceValue", Criteria.INNER_JOIN);
query.createAlias("businessReference.fleetStructure", "structure", Criteria.INNER_JOIN);
query.createAlias("structure.structureAccessLabel", "structureAccessLabel", Criteria.INNER_JOIN);

query.add( Subqueries.propertyEq("structure.structureId", createStructureSubQuery(corpFleet)));
query.add(Restrictions.eqProperty("structureAccessLabel.driverAccessLabel", "businessReferenceValue.key.label"));

query.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);



GENERATED SQL:

Code:
    select
       ---
    from
        reference_list this_,
        INDIVIDUAL individual6_,
        INDIVIDUAL_INFO individual7_,
        bus_ref_list businessre1_,
        STRUCTURE structure3_,
        STRUCTURE_ACCESS_LABEL structurea4_,
        bus_ref_access_values businessre2_
    where
        this_.reference_id=individual6_.REFERENCE_ID(+)
        and individual6_.INDIVIDUAL_ID=individual7_.INDIVIDUAL_ID(+)
        and this_.reference_id=businessre1_.reference_id
        and businessre1_.structure_id=structure3_.structure_id
        and structure3_.structure_id=structurea4_.structure_id
        and businessre1_.bus_ref_id=businessre2_.bus_ref_id
        and structure3_.structure_id = (
            select
                this0__.structure_id as y0_
            from
                STRUCTURE this0__
            where
                this0__.corp_code=?
                and this0__.bus_code=?
                and this0__.is_bus_str_element=?
        )
        and structurea4_.driver_access_label=businessre2_.bus_ref_access_label
       
       
    (MANY OF THESE)
    select
   ---
    from
   bus_ref_access_values businessre0_
    where
   businessre0_.bus_ref_id=?


MAPPINGS:


Code:
<hibernate-mapping>
   <class name="com.ge.comfin.fleet.customerpersonsync.domain.cdb.reference.BusinessReference" table="bus_ref_list">
   
   <id name="id" column="bus_ref_id" type="long"/>
       <property name="effStartDate" column="bus_ref_start_date" type="date"/>      
       <property name="effEndDate" column="bus_ref_end_date" type="date"/>
   <property name="modifyUserId" column="MODIFY_USERID" type="string" />
   <property name="modifyDateTime" column="MODIFY_DATE_TIME" type="timestamp" />       
       
   <!-- Define one-to-one Relationships -->
      
   <!-- Define the many-to-one relationships -->

   <many-to-one name="fleetStructure" class="com.ge.comfin.fleet.customerpersonsync.domain.cdb.structure.Structure">
      <column name="structure_id"/>
   </many-to-one>
   <many-to-one name="reference" class="com.ge.comfin.fleet.customerpersonsync.domain.cdb.reference.Reference" column="reference_id"/>   

   <!-- Define the one-to-many relationships (Set preferred)-->
   
   <set name="businessReferenceValues" fetch="join">
      <key column="bus_ref_id"/>
      <one-to-many class="com.ge.comfin.fleet.customerpersonsync.domain.cdb.reference.BusinessReferenceValue"/>
   </set>
     </class>
</hibernate-mapping>


Code:
<hibernate-mapping>
   <class name="com.ge.comfin.fleet.customerpersonsync.domain.cdb.reference.BusinessReferenceValue" table="bus_ref_access_values">
   <composite-id name="key" class="com.ge.comfin.fleet.customerpersonsync.domain.cdb.reference.key.BusinessReferenceValueKey">
      <key-property name="businessReferenceId" column="bus_ref_id" type="long"/>
      <key-property name="label" column="bus_ref_access_label" type="string"/>
      <key-property name="effStartDate" column="bus_ref_access_eff_date" type="date"/>
   </composite-id>
   
       <property name="value" column="bus_ref_access_value" type="string"/>   
   <property name="effEndDate" column="bus_ref_access_end_date" type="date"/>
   <property name="modifyUserId" column="MODIFY_USERID" type="string" />
   <property name="modifyDateTime" column="MODIFY_DATE_TIME" type="timestamp" />   
   
     </class>
</hibernate-mapping>


Top
 Profile  
 
 Post subject: Use createCritera instead
PostPosted: Thu Apr 19, 2007 2:57 pm 
Newbie

Joined: Thu Oct 12, 2006 6:12 pm
Posts: 8
Try changing your createAlias calls to createCritera. It has the same signature, but will fetch in the data for your association.

Stephen


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 19, 2007 3:08 pm 
Newbie

Joined: Fri Mar 30, 2007 7:15 pm
Posts: 6
So it looks like the n+1 child queries get generated because the first query used an INNER join. If I modify it to use a LEFT OUTER JOIN, the child objects are eagerly fetched (and populated) using only the first query.

Unfortunately I don't have the option of using an LEFT OUTER JOIN join (cause a table scan). This seems like a serious limitation.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 19, 2007 3:19 pm 
Newbie

Joined: Fri Mar 30, 2007 7:15 pm
Posts: 6
I tried modifying createAlias to createCriteria (see below) with no luck. The only thing that works is modifying Criteria.INNER_JOIN to Criteria.LEFT_JOIN which as I mention before is not an option for me.

Code:
Criteria query = getSession().createCriteria(BusinessReference.class);

query.createCriteria("businessReferenceValues", "businessReferenceValue", Criteria.INNER_JOIN);
query.createCriteria("businessReference.fleetStructure", "structure", Criteria.INNER_JOIN);
query.createCriteria("structure.structureAccessLabel", "structureAccessLabel", Criteria.INNER_JOIN);

query.add( Subqueries.propertyEq("structure.structureId", createStructureSubQuery(corpFleet)));
query.add(Restrictions.eqProperty("structureAccessLabel.driverAccessLabel", "businessReferenceValue.key.label"));

query.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 19, 2007 4:06 pm 
Expert
Expert

Joined: Tue Jul 11, 2006 10:21 am
Posts: 457
Location: Columbus, Ohio
You may have hit this bug. I'd grab the patch and compile 3.2.3 and see if that does it for you.


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