-->
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.  [ 3 posts ] 
Author Message
 Post subject: Best Method:Working Lazy-loading Sets + Counting Collections
PostPosted: Mon Jul 20, 2009 12:32 pm 
Newbie

Joined: Mon Feb 16, 2009 2:27 pm
Posts: 7
I'm looking for the best method(in efficientcy of time/database hits/processing/memory load)
to load a User domain class along with mapped associations of sets (but only about 20 objects from each set and a count of the objects from that set)
using Lazy-loading with @OneToMany

------------------------------------
@OneToMany sets lazy-loading
------------------------------------

Say I have a User Domain Class with 7 (and ever-growing) Sets Mapped to other domain objects using "@OneToMany" annotation

E.g. User.java
Code:
@Entity
@Table(name = "user", catalog = "myapp")
public class User implements java.io.Serializable {

   private static final long serialVersionUID = 1L;
   private String userName;
   .
   .
   .
   .
   private Set<Address> address = new HashSet();
   private Set<Message> message = new HashSet();
   private Set<Friends> friends = new HashSet();
   private Set<Refrences> refrences = new HashSet();
   private Set<Events> events = new HashSet();
   
   
   .. then getters and setters for each
   
   @OneToMany(cascade ={CascadeType.ALL})
   @JoinColumn(name="xxxxxxx")
   public Set<Address> getAddress() {
      return address;
   }
   
   public void setAddress(Set<Address> address) {
      this.address = address;
   }
   
   By x7
   
   Same for the rest of the 7 sets “Set<xxxxx>”.


Now all of these "Sets" are lazy-loaded collections.
When I want to access a certain User I search for the username and lazy-load the rest of the domain objects that correspond to that user name.

E.g. UserDaoImpl.java

Code:
@Repository("userDao")
public class UserDaoImpl implements UserDao{
   
   private SessionFactory sessionFactory;
   
   public UserDaoImpl() {}
   
   @Autowired
   public void setSessionFactory(SessionFactory sessionFactory) {
       this.sessionFactory = sessionFactory;
   }
   
   @Transactional(readOnly = true)
   public User getUserWithUserName(String userName) {
      
      Session session = sessionFactory.getCurrentSession();
      session.beginTransaction();
      
      try {   
                     
         User user = (User)session.
         createQuery("from User as user where user.userName =:userNameText").
         setString("userNameText",userName).uniqueResult();
                  
         //Initializes the sets for lazy-loading (within the same session)
         Hibernate.initialize(user.getRefrences());
         Hibernate.initialize(user.getFriends());
         Hibernate.initialize(user.getAddress());
         Hibernate.initialize(user.getMessages());
         Hibernate.initialize(user.getEvents());
         return user;
         
      } catch (HibernateException e) {
         
         return (User) null;   
         
      }finally{
         session.getTransaction().commit();
      }
   }
}


The Above code works perfectly, but I don't know how efficient it really is.
It loads the collections. But it loads the whole collection.
I only want to load a certain amount of the lazy-loaded collections
and a count for the amount of rows for each collection.

Over time the amount of objects in each collection will grow to much
and it will be a waste to load 7 entire collections to only display about 20 objects from each one.

Question 1: Is There anyway of limiting the amount of objects loaded in a lazy-loaded collection?
I've seen the "@Where" annotation can be used on Sets in Domains to make a clause, but is there a way of limit restricting with it?

----------------------------------------------------------
@ManyToOne sets lazy-loading + Counting Collections
----------------------------------------------------------

Now I've added the counting of each collection associated to the User Class.
The result of each count is set in a Transient object within the User Class.

E.g. UserDaoImpl.java + counting code added

Code:
@Repository("userDao")
public class UserDaoImpl implements UserDao{
   
   private SessionFactory sessionFactory;
   
   public UserDaoImpl() {}
   
   @Autowired
   public void setSessionFactory(SessionFactory sessionFactory) {
       this.sessionFactory = sessionFactory;
   }
   
   @Transactional(readOnly = true)
   public User getUserWithUserName(String userName) {
      
      Session session = sessionFactory.getCurrentSession();
      session.beginTransaction();
      
      try {   
                     
         User user = (User)session.
         createQuery("from User as user where user.userName =:userNameText").
         setString("userNameText",userName).uniqueResult();
                  
         //Initializes the sets for lazy-loading (within the same sessio)
         Hibernate.initialize(user.getRefrences());
         Hibernate.initialize(user.getFriends());
         Hibernate.initialize(user.getAddress());
         Hibernate.initialize(user.getMessages());
         Hibernate.initialize(user.getEvents());

         //***********Counting section within same Hibernate Session*************

         //Get size of each collcetion
         String refrenceSize = session.createFilter(user.getRefrences(), "select count(*)" ).uniqueResult().toString();
         String friendSize = session.createFilter(user.getFriends(), "select count(*)" ).uniqueResult().toString();
         String addresSize = session.createFilter(user.getAddress(), "select count(*)" ).uniqueResult().toString();
         .
         . same for Messages and Events.


         //Attach the size of each element into a Transient object into the User Domain

         user.setRefrenceSize(refrenceSize);
         user.setFriendSize(friendSize);
         .
         .
         . same for Address, Message and Events
         //***********************************************************************
         

         return user;
         
      } catch (HibernateException e) {
         
         return (User) null;   
         
      }finally{
         session.getTransaction().commit();
      }
   }
}


Question 2: Is this the best possible method for counting Collections and adding them into a class
so they can be displayed in the view? Or is there a better way of counting for many collections?
+ Whats the best way of getting them out into the view?(Adding them to Tranisent objects?)

Question 3: How many times did It hit the database?
Within the 1 Hibernate session it loaded the User Domain, and 7 sets assocated with it.
Then counted the size of 7 collections. Does each generated SQL statement mean a Database Hit?
If so I seen 8 hits, 1 for for the user and 7 for counts.
It took some time to count as it was always draging around the collections with each count.


Now I have the User Class with all its lazy-loaded collections and the count for each Collection.

So people I leave it up to your knowledge.

Whats the best possible thing to do here?

Thanks for reading,

Daxon


Top
 Profile  
 
 Post subject: Re: Best Method:Working Lazy-loading Sets + Counting Collections
PostPosted: Tue Jul 21, 2009 5:08 am 
Regular
Regular

Joined: Thu Apr 14, 2005 10:39 am
Posts: 115
Hi, if you only want to know the size,
try
Quote:
org.hibernate.annotations.LazyCollection

E.g.
Code:
@LazyCollection(value = LazyCollectionOption.EXTRA)



Greetings Michael


Top
 Profile  
 
 Post subject: Re: Best Method:Working Lazy-loading Sets + Counting Collections
PostPosted: Tue Jul 21, 2009 11:51 am 
Newbie

Joined: Mon Feb 16, 2009 2:27 pm
Posts: 7
Nice, Thanks Urmech,

I've heard of Extra lazy loading.
Now I know what it does,
Thanks I got the count working efficiently.

Just to give it out to everyone.

Code:
@OneToMany(cascade ={CascadeType.ALL})
   @JoinColumn(name="xxxx")
   @LazyCollection(value = LazyCollectionOption.EXTRA)
   public Set<Refrence> getRefrence() {
      returnRefrence;
   }

   public void setRefrence(Set<Refrence> refrence) {
      this.Refrence = Refrence;
   }


and then calling size

Code:
String refrenceSize = user.getRefrence().size();


Now limiting lazy-loading anyone?


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