9 Replies Latest reply on Nov 25, 2005 11:19 AM by renkrad

    Lazy fetch with problems

    renkrad

      I'm having a "org.apache.jasper.JasperException: failed to lazily initialize a collection of role: model.Users.userdetails, no session or session was closed" when accessing the data of a "one-to-many" relation.

      Client code :

      Users user = UsersHome.findById(1L);
      
      Iterator details = user.getUserDetails().iterator();
      
      while (details.hasNext()) {
       Userdetails userdetails = (Userdetails) details.next();
       out.println((i++) + " : " + userdetails.getValue());
      }
      



      Have searched the forum and noticed that this problem was realted to the Lazy fetch but i'm using a Local session and not a remote, and for what i was told this behaviour was not supposed to happen in a local session.
      This access is being made in a '.jsp' is it necessary to configure anything?

      Session code :
      (...)
      @Stateless
      @Local (UsersInterface.class)
      public class UsersHome implements UsersInterface {
      (...)
       public Users findById(long id) {
       log.debug("getting Users instance with id: " + id);
       try {
       Users instance = entityManager.find(Users.class, id);
       log.info("get successful");
       return instance;
       } catch (RuntimeException re) {
       log.info("get failed", re);
       re.printStackTrace();
       throw re;
       }
       }
      (...)
      }
      



      If the fetch is changed to EAGER the exception is not thrown, but the LAZY fetch is a must use due to the reasons we all know.

      Any tips of what might be the problem or the lazy fetch problem also aplies to the local?

      Daniel Campelo

        • 1. Re: Lazy fetch with problems
          bogsolomon

          I had the same problem. You are basically returning the users to a class that is not part of the trasnaction at which time it becomes detached. The references have not been initialized and when you try to get the reference you get the exception because your users are detached.


          The way I solved it was to add another method to my staless class that would do something like:

          Set<Details> getDetails(Users user)
          {
           Users u = entityManager.find(Users.class,user.id);
           Set<Details> details = u.getUserDetails();
           //not 100% sure of necessary but I think the set needs to be accessed to make sure that it is initialized
           details.size();
           return details;
          }


          • 2. Re: Lazy fetch with problems
            wesslan

             

            "BogSolomon" wrote:

            Set<Details> details = u.getUserDetails();
            //not 100% sure of necessary but I think the set needs to be accessed to make sure that it is initialized
            details.size();
            }
            


            i did a little test because I've tried earlier with just "u.getUserDetails()" and it didn't work. When I did "details.size();" everything worked nicely. But how ugly doesn't the code get when you have a complex object graph that you want to return to a client...
            Having FetchType.EAGER isn't really an option either because most of the time you don't want the entire graph.

            Is there really no other way to accomplish this? I know how you can achieve something like this in EJBQL with "join fetch" but for a complex object graph with more than two levels...

            Regards Peter

            • 3. Re: Lazy fetch with problems
              wesslan

              So finally I did what I should have done in the first place - searched the forums... :-)
              I found a couple of interesting threads about just this:
              http://www.jboss.com/index.html?module=bb&op=viewtopic&t=69112
              http://www.jboss.com/index.html?module=bb&op=viewtopic&t=62275

              Regards Peter

              • 4. Re: Lazy fetch with problems
                martinganserer

                Hello,

                your links are OK, but you can use lazy loading in jsp or servlets simply by sourround your code with a UserTransaction! This is a very convenient solution for working with complex objects on the client side!

                Regards

                Martin

                • 5. Re: Lazy fetch with problems
                  renkrad

                  Thanx for all the replys.

                  One thing i don't understand is why it's possible to define the relations in an entity but it's not possible to use it normally, without explicitly define a transaction. There is the need to get an entity data, but not need to get any data from a direct entity relation at the retreave moment (one implicit container handled transaction) but afterwards, due to some conditions, there may be the need to get the data from a direct entity relation (another implicit container handled transaction).

                  Example :

                  Users user = UsersHome.findById(1L);
                  user.getId(); // Handle this entity data
                  
                  (...) // "Many miles" of code after
                  
                  /*
                  Here the container should know that a new transaction is to be used, even if it causes some performance break down. The developer/designer/arquitect/whatever is the one who has to worry about performance and not who provides this feature.
                  */
                  Iterator details = user.getUserDetails().iterator();
                  
                  while (details.hasNext()) {
                   Userdetails userdetails = (Userdetails) details.next();
                   // Handle the other entity
                  }
                  



                  As user there shouldn't be the need to define a transaction to perform a set of selects, because no data is beeing changed/added in the db. An more, by defining UserTransactions all over the code, first, it'll stay extremlly dificult to keep, to understand it, and above all the probability of causing eventual bugs will be tremedously great. That's why the container (centralized way, as code only once to do the generic 'stuff') for it self should have the ability to perform and handle it for the developer.

                  One other thing i don't understand is why this is not considered a bug or a flaw of the specification (if it really mentions that the lazy retreaval of data should be performed in the same transaction and the container shouldn't handle it or create a new one if the client requests the data).
                  In the mapping files it's specified how to get the data, how the relation is performed which fileds are to be used in the join.


                  • 6. Re: Lazy fetch with problems
                    bogsolomon

                     

                    if it really mentions that the lazy retreaval of data should be performed in the same transaction


                    The specification does say that.

                    Basically in your code you are returning the User out of the transactions scope at which time it becomes "detached" according to the EJB3.0 specifications. If you want to obtain collections that are lazily initialized you need your entity to become attached again. Not 100% sure what the reasoning for this part of the specification is.

                    • 7. Re: Lazy fetch with problems
                      renkrad

                       

                      "BogSolomon" wrote:
                      The specification does say that..


                      Could you specify the section where it describes that the behaviour should be that way? Searched but didn't found any reference...

                      • 8. Re: Lazy fetch with problems
                        renkrad

                        From EJB 3.0 spec

                        Section "2.6 Transactions"

                        "A transaction context is required for operations on the entity manager except for operations that create
                        or execute queries. If there is no preexisting transaction context when such operations are invoked, the
                        entity manager throws the javax.persistence.TransactionRequiredException."

                        I'm i missing something...?

                        • 9. Re: Lazy fetch with problems
                          renkrad

                          Heres what's missing...

                          Section 2.3.4 Detached Entities

                          "When the persistence context ends (at the end of a transaction), managed entity instances become
                          detached.An entity may also become detached as by returning it as the result of a query that executes
                          without a transaction context. (...)"

                          This kind of behaviour goes against generic code construction... This is almost "specific code action finder" instead of building the code genericly to cover the most possible situations.