-->
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: force use of proxies in rowbean/constructor query
PostPosted: Mon Feb 25, 2013 7:04 am 
Newbie

Joined: Tue Aug 05, 2008 5:07 am
Posts: 7
Location: Dresden, Germany
Hello community,

I'm trying to execute an HQL query for a report using Hibernate 3.6.1, where I'm selecting from one of my entities "Customer" and joining an "issues" collections for some computed statistics over said issues into a row bean constructor. In order to have every row relate to exactly one customer, I'm properly grouping on the entity. The Customer entity is batch-loading enabled (batch-size="100"), as is the "issues" collection. My case is actually very basic and my approach is straight forward, so I'm simplifying away some company-secrets here:

Code:
select new company.product.report.ReportRowBean(customer, count(issues), sum(issues.effort))
from Customer customer
left join customer.issues issues
group by customer
where ...

Code:
select customer0_.ID as col_1_0_, count(issues1_.ID) as col_2_0_, sum(issues1_.EFFORT) as col_3_0_
from CUSTOMER customer0_
left join ISSUE issues1_ on issues1_.CUSTOMER_ID = customer0_.ID
group by customer0_.ID
where ...


Hibernate properly avoids to select the whole Customer entity at once because of the grouping, i.e. it only selects and groups on the customer's ID. That's fine and exactly what I want. However, when extracting rows from the result set, Hibernate immediately fires single loads for every single customer, instead of batch loading them after the result set extraction has finished, i.e. Hibernate is not creating lazy proxies as arguments to the ReportRowBean constructor but rather loads and initializes concrete customer instances for each result row before even looking at the next row. This poses an N+1 problem, that I can't seem to circumvent as it appears to be internal to Hibernate's query loading strategy. I think it has to do with Hibernate assuring a customer exists by eagerly selecting it (see "load() vs. get()" topic). I have no idea, what I could do (reconfigure, rewrite query, etc.) to prevent Hibernate from loading single customers during the result-set extraction process of the global query. Any suggestions what to do and/or where to look are very welcome. It would also help to know, if it's even possible to have Hibernate select proxies into a row bean constructor, since I have the feeling it isn't.

My customers are lazy, batchable and they don't have any one-to-one associations or fancy joined-subclasses that could trigger eagerness.

EDIT:

Replacing the aggregated computations over the issues collection with neat sub-selects to remove the grouping requirement is not an option, since I'm also using these aggregates to order the result.


Top
 Profile  
 
 Post subject: Re: force use of proxies in rowbean/constructor query
PostPosted: Mon Feb 25, 2013 10:31 am 
Newbie

Joined: Tue Aug 05, 2008 5:07 am
Posts: 7
Location: Dresden, Germany
OK, my workaround for now is to define an extra noop-property "proxy" on the customer mapping, that allows me to explicitly select an uninitialized proxy rather than an initialized instance:

Code:
<hibernate-mapping>
  <class name="company.product.model.Customer" ... >
    <id column="ID">...</id>
    ...
    <!-- virtual property to explicitly select proxy -->
    <many-to-one name="proxy" access="noop"
      column="ID" insert="false" update="false"
      cascade="none"
      class="company.product.model.Customer" />

  </class>
  ...
</hibernate-mapping>


Code:
select new company.product.report.ReportRowBean(customer.proxy, count(issues), sum(issues.effort))
from Customer customer
left join customer.issues issues
group by customer.proxy
where ...


Note, that the report query changed a little to select and group by customer.proxy rather than just customer. The resulting SQL is exactly the same, since the proxy property is virtual (access="noop"), read-only (insert="false" update="false"), mapped to the ID-column. However, since it is implicitly lazy, Hibernate refrains from eagerly initializing it, when selected.


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.