I am doing some volunteer work for the local school district. We are using Hibernate for O/R mapping, and for general searches, we don't need much of the object graph returned. So I set fetch="join" in the XML for the parts of the object graph we want returned. However, we saw that Hibernate was doing n + 1 selects. Turns out it was for this reason.
So I removed all fetch="join" entries from the XML and now use "left join fetch" in the HQL - problem solved.
But now if I want to drill down and get one entity and its object graph, I need to use"left join fetch" in the HQL and do a query rather than just loading it by its ID. The query returns a list of one object and I have to do a to grab the first object to return the entity from the DAO (which seems ugly and I'd rather avoid).
Is there any way that I can just load the object using its ID and get the object graph? The only way I can see to get the object graph is to specify in the XML (which results in the n + 1 problem for queries) or to specify "left join fetch" in the HQL. I'd rather not do a full blown query since I already have the object's primary key id.
Joe Gliniecki wrote:So I removed all fetch="join" entries from the XML and now use "left join fetch" in the HQL - problem solved.
If you use session#get(), Hibernate builds the query considering the fetch="join" mapping. This mapping is only ignored when you build your own HQL or criteria queries. So, no need to remove the fetch="join".
If you get the N+1 select problem witch fetch="join" while using session#get() then please post your mapping config.
Read this. You'll need to put lazy="false" to define the association as non-lazy, then you can can decide whether to use fetch="select" (the default) or fetch="join". If I'm not mistaken, these settings are ignored for HQL queries, so removing them shouldn't have affected the N+1 issue on your HQL queries the way you concluded.
I looked into this deeper and here is what I make out:
We were using session.load() in our DAO, but we keep our session in the DAO. Thus our business classes access the domain objects in detached mode. Thus we needed the hibernate XML to have the classes specified as lazy="false" since load() is lazy by default.
So when I had a many-to-one relationship with fetch="join" and the "one" side of the relationship had its class set to lazy="false", I had the n+1 problem. If I made the class lazy, then the n+1 problem went away, but then loading that class would not be lazy.
So I used session.get() which in non-lazy by default, and removed all lazy="false" from the classes and just have fetch="join" for the relationships and everything works fine: In one query I get the whole object graph when using get() with the object id, and in one query I get a subset of the object graph when using left join fetch in the HQL.
Hope this helps someone, but not sure why I had the n+1 problem when the class was set to lazy="false".