• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

How to retrieve the whole object graph ?

 
how jee
Greenhorn
Posts: 5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello folks,

I'm pretty new to Hibernate. I encountered some issue here when trying to retrieve the whole object graph efficiently. Here is my sample:

class A {
List listOfClassB; /* one-to-many */
List listOfClassC; /* one-to-many */
SomethingElse...
}

class B {
List listOfClassD; /* the second level of one-to-many */
SomethingElse...
}

class C {
List listOfClassE; /* the second level of one-to-many */
SomethingElse;
}

I had no problem to save the object graph, but when I tried to retrieve it efficiently, I had no luck (of course, I know I can always use getListOfClassB() and getListOfClassC(), and so on to retrieve the whole object graph step-by-step). Just I think there must a way that I can use either one or probably fewer fetchs to get the whole object graph. I tried the following, but it didn't work even for the first level (I set the lazy="true" in the config file for all the classes):

session.createCriteria(A.class)
.setFetchMode("listOfClassB", FetchMode.JOIN)
.setFetchMode("listOfClassC", FetchMode.JOIN)
.add( Expression.eq("id", id) ).list();

I guess that the reason this query didn't work probably is because it could introduce a Cartesian product result. I even could not think of a simple way to do it with a HQL. So I would like to know if I really need to do at least two queries, and merge them to construct a whole object graph? or there is any other way?

Thanks in advance
Jee
 
Paul Sturrock
Bartender
Posts: 10336
Eclipse IDE Hibernate Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I guess that the reason this query didn't work probably is because it could introduce a Cartesian product result

Yeah that's the reason. Hibernate limits you to fetching only one collection eagerly. So you are right, if you want to do this you'll need to run two queries and merge the results.
 
Sebastian Hennebrueder
Ranch Hand
Posts: 49
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello,
in HQL it should be
select a from A left join fetch a.listOfClassB left join fetch a.listOfClassC
you may consider to use
new HashSet(session.createQuery("..").list) to get each a only once.

I am wondering why your CriteriaQuery is not working, but do not have the time to check this.

lazy = true is default in Hibernate 3. You do not have to set it.

Regards
Sebastian
 
how jee
Greenhorn
Posts: 5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks a lot! Paul, Sebastian

I got the following exception when I was using the CriteriaQuery that I mentioned in my first message.

I will definitely try out the HQL suggested by Sebastian. By the way, what if the second level class B also has two/more collections, for example :

class B {
List listOfClassD; /* the second level of one-to-many */
List listOfClassF; /* the second level of one-to-many */
SomethingElse...
}

Can you still do one HQL to retrieve the whole object graph, such as

A __
|_B_
| |__ D
| |__ F
|_C_
|__ E
|__ G

Again, Thanks very much for your feedback!

Jee

----------------- Exception when using CriteriaQuery -------------
org.hibernate.exception.GenericJDBCException: could not execute query
at org.hibernate.exception.ErrorCodeConverter.handledNonSpecificException(ErrorCodeConverter.java:92)
at org.hibernate.exception.ErrorCodeConverter.convert(ErrorCodeConverter.java:80)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.loader.Loader.doList(Loader.java:1596)
at org.hibernate.loader.Loader.list(Loader.java:1577)
at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:111)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1322)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:300)
at com.thomson.phoenix.po.dao.prodgen.ProductDAO.getProductDetailById(ProductDAO.java:32)
at com.thomson.phoenix.po.prodgen.ProductDefinitionTest.testCRUD(ProductDefinitionTest.java:267)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: java.sql.SQLException: Stream has already been closed
 
how jee
Greenhorn
Posts: 5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It works, the same HQL works the sample case I mentioned in my second post. Great, thanks very much, Sebastian
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic