-->
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: Ways to eager fetch collection but restrict its size?
PostPosted: Sat Mar 15, 2008 9:01 am 
Newbie

Joined: Sat Mar 15, 2008 3:54 am
Posts: 6
Hibernate version: 3.2.3
Mapping documents:
Code:
<class name="Album" table="album" node="album">
   <set name="comments" inverse="true" lazy="true" batch-size="10" cascade="all-delete-orphan" node="album-comments">
      <key column="album_id"></key>
      <one-to-many class="Comment" node="comment"/>
   </set>
</class>
<class name="Comment" table="comment" discriminator-value="null" node="comment">
   <subclass name="AlbumComment" discriminator-value="album" >
      <many-to-one name="album" class="Album" column="album_id" embed-xml="false"></many-to-one>
   </subclass>
</class>

Code between sessionFactory.openSession() and session.close():
I use spring to manage all these. And the environment is JUnit test(Spring provided AbstractDependencyInjectionSpringContextTests which manages all transaction and session. Just want to limit eager-fetched collection size. And have tried 3 approaches.
1.
Code:
//from Album album left join fetch album.comments as comment where album.id = :albumId order by comment.createdDate desc
session.getNamedQuery("findAlbumById")
         .setLong("albumId", albumId)
         .setFetchSize(maxSize)
         .setMaxResults(maxSize)
         .uniqueResult();
   

2.
Code:
Album album = (Album) session.load(Album.class, albumId);
session.createFilter(album.getComments(), "order by createdDate")
   .setFetchSize(maxSize)
   .setMaxResults(maxSize)
   .list();
      

3.
Code:
Album album = (Album) detachedCriteria.getExecutableCriteria(session)
                     .setFetchMode("comments", FetchMode.EAGER)
                     .add(Expression.idEq(albumId))
                     .createAlias("comments", "comment")
                     .addOrder(Order.desc("comment.createdDate"))
                     .setFetchSize(maxSize)
                     .setMaxResults(maxSize)
                     .uniqueResult();
      


Full stack trace of any exception that occurs:
1.
get this worning:<firstResult/maxResults specified with collection fetch; applying in memory!>
And it fetch full collection(in sql, no limit key word at the end)

2.
No error but two separate sql.Plus if I want to iterate through or even get size of the collection, it will issue another sql call to fetch all Comments(to fetch all element for this collection since current collection has setMaxResults).

3.
It generates an inner join!?! And again, if I try to iterate the collection, it will issue a new sql call for all Comments.
If I call this method more than once,it even throw: org.hibernate.QueryException: duplicate alias: comment.

Name and version of the database you are using:
MySQL5
The generated SQL (show_sql=true):
1.
select album0_.album_id as album1_1_0_, comments1_.comment_id as comment1_3_1_, album0_.album_name as album3_1_0_, comments1_.content as content3_1_, comments1_.user_id as user6_3_1_ from album album0_ left outer join comment comments1_ on album0_.album_id=comments1_.album_id where album0_.album_id=? order by comments1_.created_date desc

2.
select album0_.album_id as album1_1_0_, album0_.album_name as album3_1_0_ from album album0_ where album0_.album_id=?
select comment0_.comment_id as comment1_3_ from comment comment0_ where comment0_.album_id = ? order by comment0_.created_date limit ?

3.
select this_.album_id as album1_1_1_, this_.album_name as album3_1_1_, comment1_.comment_id as comment1_3_0_, comment1_.created_date as created4_3_0_, comment1_.content as content3_0_, comment1_.user_id as user6_3_0_, comment1_.album_id as album7_3_0_, from album this_ inner join comment comment1_ on this_.album_id=comment1_.album_id where this_.album_id = ? order by comment1_.created_date desc limit ?

Question
Is this doable? My idea is to get an Album object with eager fetched collection Comment which will be limited to a given size.In book Hibernate in action, I remember collection always use proxy, no matter what you set. So if I return the whole Album object with incomplete collection, to presentation layer. And try to touch the collection, will it always issue another sql? But there is no session associated with it at that time. Any one know how to deal with this besides using two separate fetch(one for Album,one for Comment with setMaxResult). Thank you.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 18, 2008 1:37 am 
Newbie

Joined: Sat Mar 15, 2008 3:54 am
Posts: 6
0 reply, it must be my bad :(
But I figure out a way to achieve this with only one database call. Again correct me please if I do something stupid.
Code:
//assume Album will eager fetch collection Comment.
//Can set outer-join="true" in mapping or just use query/criteria what ever do the same trick
Album album = (Album) session.get(Album.class,id);

//start to restrict collection size
int start = 0;//start position
int end = 2;//end position
Iterator it = new ArrayIterator(album.getComments().toArray(),start,end);
Set limitedComments = new HashSet();
CollectionUtils.addAll(limitedComments,it);

//this will get rid of the collection proxy and safe to pass to presentation layer
album.setComments(limitedComments);

//now album variable will only have a maximun 2 comments in its collection and it's easy to implement pagination with this.
//and it will not cause any lazy load when I try to play arround with the collection.

return album;


The resizing is actually taken place in memory other than in database. So if collection size is huge, better use two separate database roundtrip. I managed to use a custom collection loader to restrict collection size. But that will lose pagination ability.
Side effect of this approach is the collection is no longer a proxy. If album gets reattached to session, not sure if the collection update will get picked up. I will test this later. Or maybe someone can explain a bit more on this.


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.