-->
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.  [ 16 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: How to avoid excess join to use the id of parent object?
PostPosted: Wed Jan 14, 2009 9:15 am 
Beginner
Beginner

Joined: Wed Jul 30, 2008 8:43 am
Posts: 32
Need help with Hibernate? Read this first:
http://www.hibernate.org/ForumMailingli ... AskForHelp

Hibernate version: 3.3.1

Name and version of the database you are using: Postregsq 8.2


Hello everyone. It's pretty easy question about excess fetching of data. Imagine I have two entities: Order and OrderReport. OrderReport references Order:

Code:
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "order_id")
    private Order order;


and this query returns orderReport objects without order object

Code:
session.createQuery("from OrderReport ").list()



OrderReport [id=1, order=Order[ id=null, field1=null]].
OrderReport2 [id=2, order=Order[ id=null, field1=null]].


Why order is not initialized by Hibernate using the foreign id of orderReport? See:


OrderReport [id=1, order=Order[ id=11, field1=null...]].
OrderReport2 [id=2, order=Order[ id=22, field1=null...]].


So, I have to write something like:

Code:
session.createQuery("select rep from OrderReport rep join fetch rep.order").list()


which fetches data from order too, allthough I don't need them, only the foreign id or, speaking in Hibernate language, orderReport.getOrder.getId(). That's all I need, but I have to make joins to find this foreign key. How can I avoid this?

Thanks in advance!


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 14, 2009 10:18 am 
Expert
Expert

Joined: Thu Jan 08, 2009 6:16 am
Posts: 661
Location: Germany
You can access the id (without initializing the object) of order just by invoking
Code:
orderReport.getOrder.getId()

But you have to annotate your getters instead of your fields, so that Hibernate does not initialize the order-proxy by selecting order from the database.

(see here in the part about "Certain operations do not require proxy initialization")


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 14, 2009 10:37 am 
Beginner
Beginner

Joined: Wed Apr 18, 2007 6:17 pm
Posts: 49
Location: Dominican Republic
You could also return the properties that you want from the SQL. You don't need to return the whole object.

regards,


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 14, 2009 10:58 am 
Beginner
Beginner

Joined: Wed Jul 30, 2008 8:43 am
Posts: 32
mmerder wrote:
You can access the id (without initializing the object) of order just by invoking
Code:
orderReport.getOrder.getId()

But you have to annotate your getters instead of your fields, so that Hibernate does not initialize the order-proxy by selecting order from the database.

(see here in the part about "Certain operations do not require proxy initialization")


Do you mean this?


Code:
    private Order order;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "order_id")
    public Order getOrder() {
        return order;
    }


This failed to work - "ERROR: column orderReport0_.order does not exist"

I've never used annotation for getters, it seems, that Hibernate doesn't create mapping for the column and does not understand the reference to parent entity in this case.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 14, 2009 11:02 am 
Expert
Expert

Joined: Thu Jan 08, 2009 6:16 am
Posts: 661
Location: Germany
Yes, I mean this, but you have to annotate all properties this way. Hibernate searches for annotations either on fields or on getters. It depends on where your @Id annotation is. So you have to annotate all properties in a class the same way, in this case annotate its getters.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 15, 2009 5:47 am 
Beginner
Beginner

Joined: Wed Jul 30, 2008 8:43 am
Posts: 32
I moved annotations before getters in Order class - got the error

"Could not find a setter for property checkedAllowed in class com.consult.alto.entity.Order"

the thing I had the method public boolean isCheckedAllowed() in Order class, it isn't linked to any field, it simply makes some validation actions. But it seems that Hibernate tries to bind the method to the inner field and tries to create the setter method...


Actually the idea of moving all annotations to getters doesn't seem the best one. I hope there should be some other way to solve the problem - some annotation? Any help is appreciated!


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 15, 2009 10:01 am 
Expert
Expert

Joined: Thu Jan 08, 2009 6:16 am
Posts: 661
Location: Germany
Your method isCheckedAllowed is a getter for a property matching java-bean naming conventions. So Hibernate thinks its an attribute of your entity. Annotate this method as @Transient to avoid it.

Even better, rename you method, so that it does not start with "is" or "get".


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 15, 2009 10:08 am 
Beginner
Beginner

Joined: Wed Jul 30, 2008 8:43 am
Posts: 32
mmerder wrote:
Your method isCheckedAllowed is a getter for a property matching java-bean naming conventions. So Hibernate thinks its an attribute of your entity. Annotate this method as @Transient to avoid it.

Even better, rename you method, so that it does not start with "is" or "get".


I cannot rename it, it is used on jsp page in El directive like '#{order.checkedAllowed}'. May be transient will help, I cannot now make this again, I have too many fields, and it takes time to move annotations by hand.. May be this evening. mmerder, don't you know some other way, may be annotations, it seems such a common situation!


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 15, 2009 10:16 am 
Expert
Expert

Joined: Thu Jan 08, 2009 6:16 am
Posts: 661
Location: Germany
Not many applications need to get ids of proxies that are not initialized, yet. So if you want to get it, without initializing the proxy is using access-type = property. In xml you could easily change it, annotations depend on where the @Id annotation is.

Maybe you can change it with @AccessType. I have not used it, yet, tell me if it helped you.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 15, 2009 2:07 pm 
Beginner
Beginner

Joined: Wed Jul 30, 2008 8:43 am
Posts: 32
No, @AccessType didn't help.

Frankly speaking I'm embarassed. Hibernate manuals say:

Code:
By default, Hibernate3 uses lazy select fetching for collections and lazy proxy fetching for single-valued associations.


Proxy means:
Code:
Proxy fetching - a single-valued association is fetched when a method other than the identifier getter is invoked
upon the associated object.


This what I need! Hibernate says, that the thing I need is the default action - the object is created as a proxy at the system startup and it's id is initialized when the referer is initialized from db. But this isn't true...

I tried @LazyToOne(LazyToOneOption.PROXY) but this didn't help either. The last thing (although it sounds funny :)) is really to move annotations to getters as you advise.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 16, 2009 5:46 am 
Expert
Expert

Joined: Thu Jan 08, 2009 6:16 am
Posts: 661
Location: Germany
As I said, you have to annotate your getters. I had the same problem and thats the way to solve it.

Hibernate does not know, which method is the id-getter, if you annotate your fields. I also think that could be improved, but at this moment you have to solve your problem annotating your getters instead of your fields.


Top
 Profile  
 
 Post subject: Re: How to avoid excess join to use the id of parent object?
PostPosted: Wed Feb 16, 2011 3:15 pm 
Beginner
Beginner

Joined: Wed Jul 30, 2008 8:43 am
Posts: 32
Just in a plenty of time face this problem again and now I have the large entity with more than fiveteen (!) relative parent entities. As UI part allows to use only the ids of parents (they are at most displayed as select fields and I need to show the selected one - this can be done by simple id) I need again the way to use proxies. Unfortunatelly the way, described by mmerder didn't help and I recieve the LazyInitializationException:

Code:
javax.el.ELException: /polises/calculator.xhtml @84,38 value="#{polis.paymentType.id}": org.hibernate.LazyInitializationException: could not initialize proxy - no Session
   at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:114)
   at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:190)
   at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:178)
   at javax.faces.component.UIOutput.getValue(UIOutput.java:168)


and all getters are marked as LazyToOne:
Code:
    @ManyToOne(fetch = FetchType.LAZY)
    @LazyToOne(LazyToOneOption.PROXY)
    public K4PaymentType getPaymentType() {
        return this.paymentType;
    }


This is very important and any help is appreciated! I really can not do 15 joins for this selects.


Top
 Profile  
 
 Post subject: Re: How to avoid excess join to use the id of parent object?
PostPosted: Wed Feb 16, 2011 3:42 pm 
Newbie

Joined: Wed Feb 16, 2011 1:56 pm
Posts: 7
Use the following in your Deployment Descriptor:
<mvc:interceptors>
<bean id="openSessionInViewInterceptor"
class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
</mvc:interceptors>


Top
 Profile  
 
 Post subject: Re: How to avoid excess join to use the id of parent object?
PostPosted: Wed Feb 16, 2011 4:19 pm 
Beginner
Beginner

Joined: Wed Jul 30, 2008 8:43 am
Posts: 32
Hi.

I don't want the newly created session and plenty of new queries for this object, this can be done more efficially using "join fetch" in the initial query as will produce only one select. I need to know, how to create proxies with ids in them!

Here http://blog.xebia.com/2008/03/08/advanc ... -pitfalls/ I can see:
Quote:
Instead of loading the associated row, Hibernate will create a Person object and set the id property to the value found in the BOSS column.


But in my application I see the proxy created just after em.createQuery(...).getSingleResult(), but the id property is NULL!


Top
 Profile  
 
 Post subject: Re: How to avoid excess join to use the id of parent object?
PostPosted: Wed Feb 16, 2011 5:21 pm 
Beginner
Beginner

Joined: Wed Jul 30, 2008 8:43 am
Posts: 32
Ok, I've just found the solution

http://www.catalysts.cc/blog/ejb-annota ... g/?lang=en

I've added getters on properties, but didn't do this for referenced entities as though. So, the main rule should be not to use annotations on fields, but on getter properties only in ALL entities!

Very pity, that's hibernate documentation doesn't say anything about this feature! It took really much time for me to get into this...

Update: this seems to be not a feature, but a real bug... http://opensource.atlassian.com/project ... e/HHH-3718. Instead of ugly getters annotating I will try @Access(Property) as said in the last comment


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