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.  [ 4 posts ] 
Author Message
 Post subject: Using eager and lazy loading
PostPosted: Sun Jun 06, 2010 2:41 am 
Newbie

Joined: Sun Jun 06, 2010 2:12 am
Posts: 2
I've encountered some seemingly counter-intuitive behavior when mixing eager and lazy loading of associations. Consider these entities:
Code:
@Entity
@Table(name = "parent")
public class Parent {
   @Id
   @Column(name = "id")
   private Long id;
   
   @OneToMany(mappedBy = "parent", fetch = FetchType.EAGER)
   private List<Child> children;

   public Long getId( ) { return id; }
   public void setId( Long id ) { this.id = id; }
   public List<Child> getChildren( ) { return children; }
   public void setChildren( List<Child> children ) { this.children = children; }
}

@Entity
@Table(name = "child")
public class Child {
   @Id
   @Column(name = "id")
   private Long id;
   
   @ManyToOne(fetch = FetchType.LAZY)
   private Parent parent;

   public Long getId( ) { return id; }
   public void setId( Long id ) { this.id = id; }
   public Parent getParent( ) { return parent; }
   public void setParent( Parent parent ) { this.parent = parent; }
}
Now consider this code:
Code:
@Stateless
@LocalBean
public class TestBean {
   @PersistenceContext
   private EntityManager em;

   @TransactionAttribute(value = TransactionAttributeType.SUPPORTS)
   public String test1( ) {
      String s = "";
      Child c = em.find( Child.class, 1L );
      Parent p = c.getParent( );
      List<Child> children = p.getChildren( );
      for( Child child : children ) {
         s += child.getId( ) + "\n";
      }
      return s;
   }
}
The above code throws a LazyInitializationException at runtime because p.children is lazily fetched even though the entity definition of Parent declares children to be eagerly fetched. Changing the fetch type of Child#parent to eager avoids the issue, as does "expanding" the scope of the transaction (e.g. using TransactionAttributeType.REQUIRED). Also, loading the desired instance of Parent directly (using EntityManager#find) works without issue.

Is this normal behavior? For comparison, EclipseLink (bundled with Glassfish v3) does not throw any exceptions with the exact same code. It seems odd that the fetching behavior for Parent#children would be affected by the route taken to acquire the reference to the Parent entity, but perhaps I'm missing something here. Any insights would be greatly appreciated.


Top
 Profile  
 
 Post subject: Re: Using eager and lazy loading
PostPosted: Mon Jun 07, 2010 1:40 pm 
Expert
Expert

Joined: Sat Jan 17, 2004 2:57 pm
Posts: 329
Location: In the basement in my underwear
When you load the child, your parent is marked as lazy (so it's actually a proxy). The em.find call is most likely closing the session after the child is loaded and what you're actually blowing the lazy load on is the hydration of the proxy and not the getChildren() call which would be loaded if the proxy was initialized prior to the session being closed.

_________________
Some people are like Slinkies - not really good for anything, but you still can't help but smile when you see one tumble down the stairs.


Top
 Profile  
 
 Post subject: Re: Using eager and lazy loading
PostPosted: Mon Jun 07, 2010 3:11 pm 
Newbie

Joined: Sun Jun 06, 2010 2:12 am
Posts: 2
Thanks for the reply. I think you're right - I ran a few other tests and it seems like the problem occurs when attempting to hydrate the proxy. I think I was just getting hung up on the fact that EclipseLink displayed different behavior (most likely ignoring the hint to lazy-load the association).

Thanks for your help!


Top
 Profile  
 
 Post subject: Re: Using eager and lazy loading
PostPosted: Mon Sep 06, 2010 4:59 pm 
Newbie

Joined: Thu Apr 22, 2010 11:21 am
Posts: 3
VampBoy wrote:
The em.find call is most likely closing the session after the child is loaded


I have an issue where Glassfish with Hibernate gives "lazyinit / no session" errors when accessing a List property from the object retrieved by em.find().

The same code works fine with EclipseLink. Hibernate works, too, if I use m.createQuery().getSingleResult() instead of an em.find(). [Update: I think I was wrong about the hibernate working with m.createQuery().getSingleResult(), I hadn't properly switched back from EclipseLink-- so my problem doesn't seem to be related with just em.find()].

Does calling em.find() really close the session? If so, is there a way to keep it from doing that?

I have code like this to produce the EntityManager:
Code:
@Stateless
public class MyEntityManagerProducer implements MyEntityManagerProducerLocal {
   
   private EntityManager entityManager;
   
   @Produces @MyEntityManager @ConversationScoped
   public EntityManager getEntityManager() {
      return entityManager;
   }
   
   @PersistenceContext(name="MyPersistenceUnit")
   public void setEntityManager(EntityManager entityManager) {
      this.entityManager = entityManager;
   }
}


and this to inject it:
Code:
   @Inject @MyEntityManager
   private EntityManager em;


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