-->
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.  [ 17 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Problem with using Fetching and Restrictions in Criteria qry
PostPosted: Tue Apr 17, 2007 7:13 am 
Newbie

Joined: Tue Apr 17, 2007 4:02 am
Posts: 10
Hi all


We’re having a few problems fetching associated entities for One-to-Many relationship in a relatively simple Criteria query:

1) We have to specify an additional join to unwanted entity in order to fetch the data we want.
2) Adding Restrictions to the query forces us to call Hibernate.initialize() on every element returned (despite using Fetch.JOIN).


Essentially, we've got Contractor and ContractorSkillGroup entities, and setFetchMode("contractorSkillGroups", FetchMode.JOIN) does not work as expected (I get LazyInitializationException). When, however, I add another join: .setFetchMode("contractorSkillGroups.skillGroup", FetchMode.JOIN), the thing starts working again. Note that the additional join is needed purely for the fetching to work, we do not need to load that data.

Here’s a representation of the schema:

Code:

------------   1                  *  ----------------------  1                *  ----------
| Contractor | ----------------------| ContractorSkillGroup |--------------------| Capacity |
------------                         ----------------------                      ----------
                                                  | *
                                                  |
                                                  |   
                                                  |
                                                  |
                                                  |
                                                  | 1
                                            ------------
                                           | SkillGroup |
                                            ------------


Note that ContractorSkillGroup is a proper entity with its own ID and attributes, rather than purely an expression of a Many-To-Many relationship between Contractor and SkillGroup (despite the fact that its name may sound that way).

There is another interesting twist to the problem. Since we need to allow only certain values for the ContractorSkillGroup, so when we add restrictions on it (either by .createCriteria or through creating an alias) – fetching of ContractorSkillGroup entities stops working, and the only way for us to obtain them before the session is closed is to iterate through each element of the collection with Hibernate.initialize().

My question is: Is there a way for us to avoid fetching entities we don’t need and using Hibernate.initialize()? I suspect there’s some problem with our configuration that prevents things working correctly…

Many Thanks

Alex


Versions:
Hibernate 3.2.3
Annotations: 3.3.0
Database: Oracle 10g
JDK: 1.5


Mapping documents:
Code:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
 
  <session-factory>

   <property name="connection.url">jdbc:oracle:thin....</property>
   <property name="connection.username">USERNAME</property>
   <property name="connection.driver_class">oracle.jdbc.OracleDriver</property>
   <property name="dialect">org.hibernate.dialect.OracleDialect</property>
   <property name="connection.password">PASSWORD</property>
   <property name="hibernate.show_sql">true</property>   
   <property name="hibernate.format_sql">true</property>      

    <!-- this will show us all sql statements -->
    <property name="hibernate.show_sql">true</property>
    <property name="hibernate.hbm2ddl.auto">update</property>
   <mapping class="Address"/>
   <mapping class="Audit"/>
   <mapping class="Capacity"/>
   <mapping class="Contractor"/>
   <mapping class="ContractorSkillGroup"/>
   <mapping class="ContractorUser"/>
   <mapping class="DwellingType"/>
   <mapping class="FastTrackCapacity"/>
   <mapping class="FastTrackOrder"/>
   <mapping class="FileUploaded"/>
   <mapping class="DispatchArea"/>
   <mapping class="Order"/>
   <mapping class="Platform"/>
   <mapping class="ReferenceData"/>
   <mapping class="ScheduledServiceOrder"/>
   <mapping class="ServiceOrder"/>
   <mapping class="ServiceOrderType"/>
   <mapping class="SkillGroup"/>
   <mapping class="SkillType"/>
   <mapping class="StaffUser"/>
   <mapping class="StandardCapacity"/>
   <mapping class="State"/>
   <mapping class="UnscheduledServiceOrder"/>
   <mapping class="User"/>
   <mapping class="WorkOrderType"/>
</session-factory>
</hibernate-configuration>


Code between sessionFactory.openSession() and session.close():
Code:
   @SuppressWarnings("unchecked")
   public void testFetch() throws Exception
   {
      Session session = getSession();

      Criteria rootCriteria = session.createCriteria(Contractor.class)
         .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
         .setFetchMode("contractorSkillGroups", FetchMode.JOIN)
         .setFetchMode("contractorSkillGroups.skillGroup", FetchMode.JOIN);
      
      rootCriteria
         .add(Restrictions.eq("id", 81L))
         .add(Restrictions.eq("active", true));         

//     Note: I also tried using the .createCriteria (see 3 lines below) – all to the same effect.
//                                rootCriteria
//                                          .createCriteria("contractorSkillGroups")
//                                          .add(Restrictions.eq("active", true))

      List<Contractor> list = rootCriteria.list();
      
//     Note: When Restrictions on contractorSkillGroups are commented out, Hibernate.initialize() is not required
      for (Contractor c : list)
      {
                    Hibernate.initialize(c.getContractorSkillGroups());
      }
      
      session.close();
      
      System.out.println("Results found: " + list.size());                  
      for (Contractor contr : list)
      {
         System.out.println(contr);
         System.out.println("\t\t" + contr.getContractorSkillGroups());
         for (ContractorSkillGroup csg : contr.getContractorSkillGroups())
         {
            System.out.println(csg);
         }
      }            
   }   



Full stack trace of any exception that occurs:
The JUnit test above runs successfully, however when the line containing Hibernate.initialize() is commented out, the following exception occurrs:
Code:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: Contractor.contractorSkillGroups, no session or session was closed
   at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358)
   at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)
   at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:343)
   at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:86)
   at org.hibernate.collection.PersistentSet.toString(PersistentSet.java:309)
   at java.lang.String.valueOf(String.java:2577)


The generated SQL (show_sql=true):
Code:
    select
        this_.id as id3_2_,
        this_.OPT_LOCK as OPT2_3_2_,
        this_.ACTIVE as ACTIVE3_2_,
        this_.DISPATCH_FILE_LOCATION as DISPATCH4_3_2_,
        this_.EMAIL_CC as EMAIL5_3_2_,
        this_.EMAIL_TO as EMAIL6_3_2_,
        this_.END_DATE as END7_3_2_,
        this_.EXTERNAL_NRC_ID as EXTERNAL8_3_2_,
        this_.EXTERNAL_SUPERVISOR_ID as EXTERNAL9_3_2_,
        this_.FAST_TRACK_CAPACITY_VAR as FAST10_3_2_,
        this_.NAME as NAME3_2_,
        this_.START_DATE as START12_3_2_,
        csg1_.id as id4_0_,
        csg1_.OPT_LOCK as OPT2_4_0_,
        csg1_.ACTIVE as ACTIVE4_0_,
        csg1_.CONTRACTOR_ID as CONTRACTOR7_4_0_,
        csg1_.DAILY_STANDARD_CAPACITY as DAILY4_4_0_,
        csg1_.FAST_TRACK_ALLOWED as FAST5_4_0_,
        csg1_.SKILL_GROUP_ID as SKILL6_4_0_,
        skillgroup4_.id as id12_1_,
        skillgroup4_.OPT_LOCK as OPT2_12_1_,
        skillgroup4_.DISPATCH_AREA_ID as DISPATCH4_12_1_,
        skillgroup4_.SKILL_TYPE_ID as SKILL3_12_1_
    from
        CONTRACTOR this_,
        CONTRACTOR_SKILL_GROUP csg1_,
        SKILL_GROUP skillgroup4_
    where
        this_.id=csg1_.CONTRACTOR_ID
        and csg1_.SKILL_GROUP_ID=skillgroup4_.id(+)
        and this_.id=?
        and this_.ACTIVE=?
        and csg1_.ACTIVE=?


Thanks again,

A.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 17, 2007 8:35 am 
Regular
Regular

Joined: Thu Dec 22, 2005 7:47 am
Posts: 62
Location: Czech Republic
what about moving your code inside the session? it seems to me that, you need that data -- you ask for printing them out (but that is probably not a solution you seek for).

pls, how does the sql look like when you disable the second restriction?

not sure if this is the solution, but i would guess that without the first restriction, you would have unitialized collection "contractorSkillGroups", without the second restriction you end up with initialized collection, but with uninitialized elements inside the collection (see javadoc for Hibernate.initialize()).

the second restriction ensures, that not only the collection, but also the elements will be initialized.

If ever you need to access some of those elements it is suitable to fetch them inside the session to prevent n+1 selects, imho.

regards, m.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 17, 2007 8:41 am 
Expert
Expert

Joined: Tue Jul 11, 2006 10:21 am
Posts: 457
Location: Columbus, Ohio
A:

#1 - Nice posting!

#2 - I don't think it would change the result, but you can try to comment out the result transformer, since you are restricting by primary key, you should get only one root entity back. I'd see what happens in any case.

#3 - Let's try this:

Code:
      Criteria rootCriteria = session.createCriteria(Contractor.class)
         .add(Restrictions.eq("id", 81L))
         .add(Restrictions.eq("active", true))
         .createCriteria("contractorSkillGroups", Criteria.LEFT_JOIN)
           .add(Restrictions.eq("active", true);


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 17, 2007 9:21 am 
Expert
Expert

Joined: Tue Jul 11, 2006 10:21 am
Posts: 457
Location: Columbus, Ohio
Just remembered, the contractorSkillGroups collection will not be prefiltered, so be careful of that. You can use the ALIAS_TO_ENTITY_MAP transformer to retrieve only the matching entities in the collection.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 17, 2007 11:30 pm 
Newbie

Joined: Tue Apr 17, 2007 4:02 am
Posts: 10
Mar,

Thanks for your suggestions.

mar wrote:
what about moving your code inside the session?

I understand, you mean doing everything before session is closed (pls correct me if I am wrong). We are supposed to deploy this stuff in portal server, and for a number of reasons we need to keep presentation separate from business logic. Using OpenSessionInView is not an option for us.

mar wrote:
pls, how does the sql look like when you disable the second restriction?

Restrictions: please note there was a slight error in my previous post (the second set of restrictions was commented out while it shouldn't have been).

These are the restrictions that we NEED:
Code:
      rootCriteria
         .add(Restrictions.eq("id", 81L))
         .add(Restrictions.eq("active", true))
      ;
      
      rootCriteria
         .createCriteria("contractorSkillGroups")
         .add(Restrictions.eq("active", true));   


They produce the SQL below:
Code:
     select
        this_.id as id3_2_,
        this_.OPT_LOCK as OPT2_3_2_,
        this_.ACTIVE as ACTIVE3_2_,
        this_.DISPATCH_FILE_LOCATION as DISPATCH4_3_2_,
        this_.EMAIL_CC as EMAIL5_3_2_,
        this_.EMAIL_TO as EMAIL6_3_2_,
        this_.END_DATE as END7_3_2_,
        this_.EXTERNAL_NRC_ID as EXTERNAL8_3_2_,
        this_.EXTERNAL_SUPERVISOR_ID as EXTERNAL9_3_2_,
        this_.FAST_TRACK_CAPACITY_VAR as FAST10_3_2_,
        this_.NAME as NAME3_2_,
        this_.START_DATE as START12_3_2_,
        contractor1_.id as id4_0_,
        contractor1_.OPT_LOCK as OPT2_4_0_,
        contractor1_.ACTIVE as ACTIVE4_0_,
        contractor1_.CONTRACTOR_ID as CONTRACTOR6_4_0_,
        contractor1_.DAILY_STANDARD_CAPACITY as DAILY4_4_0_,
        contractor1_.FAST_TRACK_ALLOWED as FAST5_4_0_,
        contractor1_.SKILL_GROUP_ID as SKILL7_4_0_,
        skillgroup4_.id as id12_1_,
        skillgroup4_.OPT_LOCK as OPT2_12_1_,
        skillgroup4_.DISPATCH_AREA_ID as DISPATCH3_12_1_,
        skillgroup4_.SKILL_TYPE_ID as SKILL4_12_1_
    from
        CONTRACTOR this_,
        CONTRACTOR_SKILL_GROUP contractor1_,
        SKILL_GROUP skillgroup4_
    where
        this_.id=contractor1_.CONTRACTOR_ID
        and contractor1_.SKILL_GROUP_ID=skillgroup4_.id(+)
        and this_.id=?
        and this_.ACTIVE=?
        and contractor1_.ACTIVE=?


When the second restriction (on contractorSkillGroups) is commented out, the SQL generated is:
Code:
    select
        this_.id as id3_2_,
        this_.OPT_LOCK as OPT2_3_2_,
        this_.ACTIVE as ACTIVE3_2_,
        this_.DISPATCH_FILE_LOCATION as DISPATCH4_3_2_,
        this_.EMAIL_CC as EMAIL5_3_2_,
        this_.EMAIL_TO as EMAIL6_3_2_,
        this_.END_DATE as END7_3_2_,
        this_.EXTERNAL_NRC_ID as EXTERNAL8_3_2_,
        this_.EXTERNAL_SUPERVISOR_ID as EXTERNAL9_3_2_,
        this_.FAST_TRACK_CAPACITY_VAR as FAST10_3_2_,
        this_.NAME as NAME3_2_,
        this_.START_DATE as START12_3_2_,
        contractor2_.CONTRACTOR_ID as CONTRACTOR6_4_,
        contractor2_.id as id4_,
        contractor2_.id as id4_0_,
        contractor2_.OPT_LOCK as OPT2_4_0_,
        contractor2_.ACTIVE as ACTIVE4_0_,
        contractor2_.CONTRACTOR_ID as CONTRACTOR6_4_0_,
        contractor2_.DAILY_STANDARD_CAPACITY as DAILY4_4_0_,
        contractor2_.FAST_TRACK_ALLOWED as FAST5_4_0_,
        contractor2_.SKILL_GROUP_ID as SKILL7_4_0_,
        skillgroup3_.id as id12_1_,
        skillgroup3_.OPT_LOCK as OPT2_12_1_,
        skillgroup3_.DISPATCH_AREA_ID as DISPATCH3_12_1_,
        skillgroup3_.SKILL_TYPE_ID as SKILL4_12_1_
    from
        CONTRACTOR this_,
        CONTRACTOR_SKILL_GROUP contractor2_,
        SKILL_GROUP skillgroup3_
    where
        this_.id=contractor2_.CONTRACTOR_ID(+)
        and contractor2_.SKILL_GROUP_ID=skillgroup3_.id(+)
        and this_.id=?
        and this_.ACTIVE=?

Note the outer join on CONTRACTOR_SKILL_GROUP - denoted by (+) in Oracle sql.
Also note that When the restriction on contractorSkillGroups is commented out, Hibernate.initialize could be commented out as well and the test will still pass.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 18, 2007 12:33 am 
Newbie

Joined: Tue Apr 17, 2007 4:02 am
Posts: 10
Ananasi,

Thanks for your posting. Your suggestion #3 worked really well and solved the problem completely!!

There is a slight complication, though: I understand
Code:
public Criteria createCriteria(String associationPath, int joinType)
exists only in Criteria but not in DetachedCriteria...

At the moment, our DAOs call DetachedCriteria, so we'll have to do a substantial refactoring to convert everything to use Criteria. Our app utilises Spring which handles DetachedCriteria with much more elegance (essentially, using "attached" Criteria implies doing everything inside HibernateCallback - which is of course doable but is quite different from what we've got at the moment, hence the expected refactoring effort).

If you can think of a way to make it work with DetachedCriteria - please let us know...


Cheers,

Alex


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 18, 2007 2:27 am 
Newbie

Joined: Tue Apr 17, 2007 4:02 am
Posts: 10
Moonee Valley wrote:
...and solved the problem completely!!


Oops, just noticed that we still need the unnecessary join on SkillGroup (otherwise a LazyInitializationException comes up).

Setting FetchType.EAGER on the ContractorSkillGroup side of the ContractorSkillGroup - SkillGroup relationship is a substitute for the additional join:

Code:
@Entity
@Table(name="CONTRACTOR_SKILL_GROUP")
public class ContractorSkillGroup extends LogicalDeleteSupportEntityImpl
{
   @ManyToOne (optional=false, fetch=FetchType.EAGER)
   @JoinColumn (name="SKILL_GROUP_ID")
   private  SkillGroup skillGroup;



Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 18, 2007 2:52 am 
Regular
Regular

Joined: Thu Dec 22, 2005 7:47 am
Posts: 62
Location: Czech Republic
hi,

use DetachedCriteria.setFetchMode().

Code:
DetachedCriteria beop = DetachedCriteria.forClass(getClazz())
    .setFetchMode("operation", FetchMode.JOIN)
    .createCriteria("operation")
    .add(Restrictions.eq("class", "book_entry"));


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 18, 2007 4:06 am 
Newbie

Joined: Tue Apr 17, 2007 4:02 am
Posts: 10
Mar,

Thanks for your post. We’d love to use DetachedCriteria – however, as it turns out, there is some difference between that class and “attached” Criteria.

Our code using attached Criteria (as per Ananasi's suggestion):
Code:
      Criteria rootCriteria = session.createCriteria(Contractor.class)
         .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
         .setFetchMode("contractorSkillGroups", FetchMode.JOIN);
      
      rootCriteria
         .add(Restrictions.eq("id", 81L))
         .add(Restrictions.eq("active", true))
         .createCriteria("contractorSkillGroups", Criteria.LEFT_JOIN)
                  .add(Restrictions.eq("active", true));          
      
      List<Contractor> list = rootCriteria.list();


Resulting SQL:
Code:
    select
        this_.id as id3_2_,
        this_.OPT_LOCK as OPT2_3_2_,
        this_.ACTIVE as ACTIVE3_2_,
        this_.DISPATCH_FILE_LOCATION as DISPATCH4_3_2_,
        this_.EMAIL_CC as EMAIL5_3_2_,
        this_.EMAIL_TO as EMAIL6_3_2_,
        this_.END_DATE as END7_3_2_,
        this_.EXTERNAL_NRC_ID as EXTERNAL8_3_2_,
        this_.EXTERNAL_SUPERVISOR_ID as EXTERNAL9_3_2_,
        this_.FAST_TRACK_CAPACITY_VAR as FAST10_3_2_,
        this_.NAME as NAME3_2_,
        this_.START_DATE as START12_3_2_,
        contractor1_.CONTRACTOR_ID as CONTRACTOR7_4_,
        contractor1_.id as id4_,
        contractor1_.id as id4_0_,
        contractor1_.OPT_LOCK as OPT2_4_0_,
        contractor1_.ACTIVE as ACTIVE4_0_,
        contractor1_.CONTRACTOR_ID as CONTRACTOR7_4_0_,
        contractor1_.DAILY_STANDARD_CAPACITY as DAILY4_4_0_,
        contractor1_.FAST_TRACK_ALLOWED as FAST5_4_0_,
        contractor1_.SKILL_GROUP_ID as SKILL6_4_0_,
        skillgroup4_.id as id12_1_,
        skillgroup4_.OPT_LOCK as OPT2_12_1_,
        skillgroup4_.DISPATCH_AREA_ID as DISPATCH3_12_1_,
        skillgroup4_.SKILL_TYPE_ID as SKILL4_12_1_
    from
        CONTRACTOR this_,
        CONTRACTOR_SKILL_GROUP contractor1_,
        SKILL_GROUP skillgroup4_
    where
        this_.id=contractor1_.CONTRACTOR_ID(+)
        and contractor1_.SKILL_GROUP_ID=skillgroup4_.id(+)
        and this_.id=?
        and this_.ACTIVE=?
        and contractor1_.ACTIVE=?


Note the two outer joins above.

Code using DetachedCriteria:
Code:
DetachedCriteria rootCriteria = DetachedCriteria.forClass(Contractor.class)
         .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
         .setFetchMode("contractorSkillGroups", FetchMode.JOIN)
         .setFetchMode("contractorSkillGroups.skillGroup", FetchMode.JOIN)
         ;
      
      rootCriteria         
         .add(Restrictions.eq("id", 81L))
         .add(Restrictions.eq("active", true))               
   
         .createCriteria("contractorSkillGroups")
         .add(Restrictions.eq("active", true))
         ;      


Note I wasn't entirely sure where to stick setFetchMode statements, so I put them in the very beginning (if you've got better suggestions please let us know).

Resulting SQL:
Code:
    select
        this_.id as id3_2_,
        this_.OPT_LOCK as OPT2_3_2_,
        this_.ACTIVE as ACTIVE3_2_,
        this_.DISPATCH_FILE_LOCATION as DISPATCH4_3_2_,
        this_.EMAIL_CC as EMAIL5_3_2_,
        this_.EMAIL_TO as EMAIL6_3_2_,
        this_.END_DATE as END7_3_2_,
        this_.EXTERNAL_NRC_ID as EXTERNAL8_3_2_,
        this_.EXTERNAL_SUPERVISOR_ID as EXTERNAL9_3_2_,
        this_.FAST_TRACK_CAPACITY_VAR as FAST10_3_2_,
        this_.NAME as NAME3_2_,
        this_.START_DATE as START12_3_2_,
        contractor1_.id as id4_0_,
        contractor1_.OPT_LOCK as OPT2_4_0_,
        contractor1_.ACTIVE as ACTIVE4_0_,
        contractor1_.CONTRACTOR_ID as CONTRACTOR7_4_0_,
        contractor1_.DAILY_STANDARD_CAPACITY as DAILY4_4_0_,
        contractor1_.FAST_TRACK_ALLOWED as FAST5_4_0_,
        contractor1_.SKILL_GROUP_ID as SKILL6_4_0_,
        skillgroup4_.id as id12_1_,
        skillgroup4_.OPT_LOCK as OPT2_12_1_,
        skillgroup4_.DISPATCH_AREA_ID as DISPATCH3_12_1_,
        skillgroup4_.SKILL_TYPE_ID as SKILL4_12_1_
    from
        CONTRACTOR this_,
        CONTRACTOR_SKILL_GROUP contractor1_,
        SKILL_GROUP skillgroup4_
    where
        this_.id=contractor1_.CONTRACTOR_ID
        and contractor1_.SKILL_GROUP_ID=skillgroup4_.id(+)
        and this_.id=?
        and this_.ACTIVE=?
        and contractor1_.ACTIVE=?


Note that there is now an inner, rather than outer join between CONTRACTOR and CONTRACTOR_SKILL_GROUP.

I'm only hypothesising here, but maybe the inner join between CONTRACTOR and CONTRACTOR_SKILL_GROUP prevents CONTRACTOR_SKILL_GROUP data from being loaded properly?

A significant difference between "attached" and Detached Criteria is that the former supports LEFT_JOIN
Code:
   .createCriteria("contractorSkillGroups", Criteria.LEFT_JOIN)
while the latter doesn't.

Nevertheless, when I set FetchType.EAGER for Contractor.contractorSkillGroups, the thing works fine even with the DetachedCriteria. Not sure whether we should enable eager fetching on that association as there are about 200 CONTRACTOR_SKILL_GROUP records per each CONTRACTOR, so the performance hit may be rather significant (I guess caching may help here but it has its own downsides).

Cheers,

A.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 18, 2007 4:16 am 
Regular
Regular

Joined: Thu Dec 22, 2005 7:47 am
Posts: 62
Location: Czech Republic
well, now im just guessing, but:

1. setting EAGER for an application is not a very good idea, unless absolutely nescessary imho, setting it for just this query is ok, you may check
Code:
http://www.hibernate.org/hib_docs/v3/reference/en/html/performance.html#performance-fetching
for some ideas and look also at some hibernate properties (probably you have hibernate.max_fetch_depth set to 1 at least)

2. i would do it like this:

Code:
DetachedCriteria rootCriteria = DetachedCriteria.forClass(Contractor.class)
         .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
         .setFetchMode("contractorSkillGroups", FetchMode.JOIN)
         ;
     
      rootCriteria         
         .add(Restrictions.eq("id", 81L))
         .add(Restrictions.eq("active", true))               
   
         .createCriteria("contractorSkillGroups")
         .setFetchMode("skillGroup", FetchMode.JOIN)
         .add(Restrictions.eq("active", true))
         ;


ie. attach the fetch strategy to the criteria it belongs to.

regards, m.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 18, 2007 4:52 am 
Newbie

Joined: Tue Apr 17, 2007 4:02 am
Posts: 10
Mar,

Thanks for the suggestions.

1. - I've tried the following hibernate properties (they did not have any effect).
Code:
<property name="hibernate.use_outer_join">true</property>
<property name="hibernate.max_fetch_depth">5</property>
About to give that chapter on Fetching Strategies another read.

2. - Tried what you suggested as well as a few other combinations. No much luck, unfortunately...

Cheers,

A.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 18, 2007 5:33 am 
Regular
Regular

Joined: Thu Dec 22, 2005 7:47 am
Posts: 62
Location: Czech Republic
now im confused a bit -- looking at hib3.2.2 javadoc, the FetchMode.JOIN == FetchMode.EAGER.

Quote:
Nevertheless, when I set FetchType.EAGER for Contractor.contractorSkillGroups, the thing works fine even with the DetachedCriteria. Not sure


You say it works with EAGER and not with JOIN?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 18, 2007 9:00 am 
Expert
Expert

Joined: Tue Jul 11, 2006 10:21 am
Posts: 457
Location: Columbus, Ohio
Just FYI, there is a bug, HHH-952, that affects joins in DetachedCriteria instances. I had to manually patch Hibernate with the supplied patch to get DetachedCriteria to join properly.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 18, 2007 8:49 pm 
Newbie

Joined: Tue Apr 17, 2007 4:02 am
Posts: 10
mar wrote:
You say it works with EAGER and not with JOIN?


Mar, I meant that setting FetchType.EAGER (as opposed to LAZY) on the contractorSkillGroups association of the actual Contractor class eliminates the problem. Of course, as you had pointed out earlier, it's not a very good solution since a bunch of contractorSkillGroups will be loaded every time a contractor is loaded.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 19, 2007 1:59 am 
Regular
Regular

Joined: Thu Dec 22, 2005 7:47 am
Posts: 62
Location: Czech Republic
there is one more thing i realized now, not sure it helps. the ContractorSkillGroup is always a child, right?

Recentley i encountered a problem with eager fetching when following the association from child->parent (http://forum.hibernate.org/viewtopic.php?t=972526&highlight=).

Though the query generated was fine (as yours) hibernate ignores the loaded entities and issued another n selects (n+1 problem).

Once i changed the query just from (schematically, BookEntry is parent to BookEntryOperation):

Code:
select beop from BookEntryOperation beop
left join fetch beop.bookEntry be


to

Code:
select be from BookEntry be
left join fetch be.operation beop


it helped. you may try to rewrite the query in hql, returning a tuple, but that is without guarantee and it would require a HibernateCallback to obtain a session for hql just to try it (and you want detached criteria).

Code:
select c, sg
from Contractor c
left join fetch c.contractorSkillGroups csg
left join fetch csg.skillGroup sg
where c.active = true
...


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