-->
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.  [ 9 posts ] 
Author Message
 Post subject: loading dynamically graph class with collections
PostPosted: Sun May 07, 2006 8:39 pm 
Newbie

Joined: Sun May 07, 2006 8:08 pm
Posts: 4
Hi!
Supose the next structure or class diagram: class A contains a collection of class B and class B contains a collection of class C and finally class C contains a collection of class D.
All this collections mappings are lazy="true" in all classes A,B,C.
I can load dynamically the instances of B in class A in this way:

Code:
Criteria criteria = session.createCriteria(A.class);
criteria.setFetchMode("collectionB",  FetchModel.JOIN);


But, my problem is, I want to load all graph of instances B,C,D: so I try with the next code:

Code:
Criteria criteria = session.createCriteria(A.class);
criteria.setFetchMode("collectionB",  FetchModel.JOIN);
criteria.createCriteria("collectionB",  aliasB)
        .setFetchMode("collectionC", FetchModel.JOIN);
criteria.createCriteria("aliasB.collectionC",  aliasC)
        .setFetchMode("collectionD", FetchModel.JOIN);


This code is ok, but the result of criteria execution is a collection of many repeated instances of class A. This is logic because the generated SQL use JOIN with JOIN ... etc.

Finally, Anybody know if exist any solution to solve this problem ?
I can do it with differents criterias but the architecture of the system not allow this solution.

Thanks in advance !
Fede


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 08, 2006 12:50 am 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
Set your result transformer to DISTINCT_ROOT_ENTITY.
Code:
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

_________________
Code tags are your friend. Know them and use them.


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 08, 2006 9:07 am 
Newbie

Joined: Sun May 07, 2006 8:08 pm
Posts: 4
Hello, thanks for your quickly response.
Is true, with code:

Code:
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);


the results is a unique instance of A .... but now the instances of B, C and D
are repeated too.
I try with this code:

Code:
Criteria criteria = session.createCriteria(A.class);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.setFetchMode("collectionB",  FetchModel.JOIN);
criteria.createCriteria("collectionB",  aliasB)
        .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
        .setFetchMode("collectionC", FetchModel.JOIN);
criteria.createCriteria("aliasB.collectionC",  aliasC)
        .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
        .setFetchMode("collectionD", FetchModel.JOIN);


But now criteria execution throws a LazyInitializationException ¿?
What is the problem here ?


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 08, 2006 6:51 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
What do you mean when you say "but now the instances of B, C and D
are repeated too."? You are querying for instances of A. The only reason you're getting Bs, Cs or Ds is because they are on an association or in a collection of A. If an A has two identical Bs, then you will get that B instance twice: if you got anything else, the A object you got would be wrong. Similarly, if two different instances of A both share the same instance of B, then both As must contain that B... otherwise, the A instances would be wrong.

The reason you're getting exceptions when putting a root entity transformer on a non-root entity is because that's illegal. You can't do it. Put the transformer on the root entity criteria and nowhere else.

_________________
Code tags are your friend. Know them and use them.


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 08, 2006 10:55 pm 
Newbie

Joined: Sun May 07, 2006 8:08 pm
Posts: 4
First, sorry for my bad english ;)
All you said is perfectly and I understand. I will try to correctly explain the problem:
An instance of A supose a1 has references to (b1, b2, ..., bn) "size n" instances of class B.

b1 has references to (c1, c2, c3) "size 3"
b2 has references to (c4, c5, c6) "size 3"
.
.
.
bn has references to (cn-2, cn-1, cn) "size 3"
Finally
c1 has references to (d1, d2) "size 2"
c2 has references to (d3, d4) "size 2"
.
.
.
cn has references to (dn-1, dn) "size 2"

Well, my goal is load this graph (or tree) in memory with a unique criteria. The code's used until now, get a unique instance of A, a1, but each bi is repeated the same quantity than references size of C (in Cs collection of bi). Then the same problem exist with instances of class C. Each ci is repeated the same quantity than references size of D (in Ds collection of ci).
Graphically:
a1 -> (b1, b1, b1, b2, b2, b2, ..........., bn, bn, bn)
each b1 -> (c1, c1, c2, c2, c3, c3)
each c1 -> (d1, d2)
each c2 -> (d3, d4)
.
each b2 -> (c4, c4, c5, c5, c6, c6)
. each c4 -> (d7, d8)
. .
each bn -> (cn-2, cn-2, cn-1, cn-1, cn, cn)
.
.

I hope everything be clear enough!


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 08, 2006 11:05 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
I've heard of this, but it has never happened to me. Perhaps it's because I almost never use nested criteria, I prefer aliases, when appropriate. Try changing your original query to use aliases:
Code:
Criteria criteria = session.createCriteria(A.class);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.createAlias("collectionB", "b");
criteria.createAlias("b.collectionC", "c");
criteria.createAlias("c.collectionD", "d");
criteria.setFetchMode("c.collectionD", FetchModel.JOIN);
This has the added bonus that you only have to set the fetch mode once: after all, in order to fetch the instances of D, the B and C instances must also be fetched.

I'm not sure if aliases work with setFetchMode, I've never had to try that. Play around with it, I'm sure it'll be easy to sort out, even if you have to fully list out the path.

_________________
Code tags are your friend. Know them and use them.


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 09, 2006 10:48 am 
Newbie

Joined: Sun May 07, 2006 8:08 pm
Posts: 4
Hi, I've tried with your suggestion but throw an LazyInitializationException when access to a1.collectionB, failed to lazily initialize a collection of role: somePackage.A.collectionB.
I can't find another solution. If you have another suggestion please tell me.
Thank you :)


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 09, 2006 10:58 am 
Expert
Expert

Joined: Tue Apr 25, 2006 12:04 pm
Posts: 260
I suppose you are getting LazyInitializationException because you are accessing information in collection objects after closing session. If not could you post the exception trace and the code snippet.


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 09, 2006 6:09 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
If it's not working as is, play around with the setFetchMode method. As I posted before, I've never used it with aliases, so I'm not sure about its limitations. Try it without aliases (setFetchMode("collectionB.collectionC.collectionD", FetchMode.JOIN), try it once per join, etc. Play around with it until it does what you want.

_________________
Code tags are your friend. Know them and use them.


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