14 Replies Latest reply on Aug 10, 2007 8:00 AM by deepasenthil

    EJB3 - how to work with lazy loading

    martinganserer

      Hi,

      lazy load works transparently on your application server!
      That means that you don't have to tell JBOSS to load lazy attributes or collections.
      If you annotate some attributes or collections with lazy, data will be fetched from the database server only on demand. On demand means that data will be fetched only if you access a collection or an attribute.

      For example:

      // Lets get an order from the persistent source
      Order order = DAOOrder.getOrderById(orderId);
      
      // JBOSS loaded all order data, but not the lazy collection
      System.out.println(order.getId);
      
      // Now for instance we want to display all line items
      // By calling the getLineItems method the application server loads the data.
      for (Iterator iter = order.getLineItems().iterator(); iter.hasNext();)
      {
       OrderItem item = (OrderItem)iter.next();
       System.out.println("Order item ID:" + item.getId() );
      }


      But be aware of lazy load in distributed applications! The lazy load mechanism only works on the application server itself. If you are working with remote clients (over RMI) you cannot expect the client to know what lazy load is.

      That means if you want to send a client the whole order object with all line items you must force the lazy load on the application server. If you don't the client only gets the order object with an empty collection.

      Did this explanation help you?





        • 1. Re: EJB3 - how to work with lazy loading
          wrussell

          Hi Martin,

          Yes, I think it does. I guess what you're saying is that I need two Session bean methods - one just returns the Order object, the other gets the Order object and then also accesses the Lines collection before returning, thereby firing the lazy loading? This way, I can choose whether or not I want detail. Would that be right?

          Can't think why it didn;t occur to me to at least try this, but thanks very much for the help!

          Wayne

          • 2. Re: EJB3 - how to work with lazy loading
            martinganserer

            Hi again,

            your are right! One possible solution for handling this problem is using two session bean methods. But indeed I am a bit afraid of this solution.
            On the one hand it is not a good architecture and on the other hand you will run into another problem:
            You have one method (A) to get only the blank order object and a second method (B) to get the order object with all order lines! Now for example the order line item entity has a lazy association to the product entity.
            If you now would call method B on the remote client you will get the order object with all line items but you couldn't find any product information. This is absolutely horrible!
            For myself I can only come to one conclusion: Never use Entity Java Beans on remote clients directly!
            In my EJB3 framework I will use simple Beans in a layer between client and business services to map all information I need in different use cases. For solving this problem I would generate two order beans. A truncated bean for the order object only. And a bean for holding all information like flat order lines including the product ID.

            What do you think?

            • 3. Re: EJB3 - how to work with lazy loading
              wrussell

              Sorry, I wasn't really suggesting the two-method approach as a full solution, I was just describing a simple technical possibility, to see if I'd understood you correctly.

              I agree with your conclusion, that it is simply too dangerous to use lazy-loaded EJB3's in a remote application - there's too much scope for uninitialised objects to rear up. And I agree that your solution solves the problem. I'm not very happy about it all, though, I must say! Managed Persistence is supposed to make your life easier, and EJB3 is supposed to make it easier still. The clear and obvious intent of the EJB3 POJO is that you can use it in your application like any other normal Java object - pass it around, subclass it, put it in lists, read and update it in normal OO fashion, whatever you like - and it will look after the persistence of that object transparently (or almost transparently).

              It seems to me that we are a long way from this if your only options are to make every relation Eager (ie., load the entire database into memory) or decide that your application is going to be non-distributed! What application these days *isn't* distributed? The extra layer of plain beans you describe sound to me exactly like Value Objects - I thought those were going to be redundant now!?

              I not sure I see what benefit EJB3 persistence gives you over just using Hibernate in session beans, or even just writing your own persistence classes and calling them from session beans (I've always thought it a curious notion that one benefit of ORM solutions is that they save the developer from having to know SQL. After all, the type of SQL that Hibernate is typically generating for you could be thoroughly learned in about 4 minutes by a seven-year-old. In fact, I'm going to take out four minutes later on today and teach my seven-year-old the necessary SQL, just to prove it!)

              Sorry to go on. Are you not a little disappointed, though, that EJB3 still requires you to use Value Objects? I know there are arguments that this is the correct architecture anyway, but that's a different argument. The whole point of EJB3 was to provide transparent persistence for plain objects and get rid of the whole shebang of interfaces and support classes. The continued need for Value Objects seems to me to be contrary to this intention, though I'd agree that it is still simpler than EJB2 (though not any simpler or more functional than just using Hibernate inside session beans).

              Wayne

              • 4. Re: EJB3 - how to work with lazy loading
                heinrich

                Hi,

                i'm running in to strange problem using your hints.
                I'm using jboss 4.0.3 RC3.
                I just do not want to fetch all relations of a table.
                I marked all fields in my entity with fetchtype LAZY on the On2man and many2one etc.
                But it doesn't function.
                I use a session bean to obtain the entity and write it out to the client.
                But all the data from the dependecies are there. Why?

                I can remember having read, that fetchtype LAZY is the default.

                I'm evaluating wether to use Value and lightValue objects in my application.
                Is there a good howto for this topic in special for ejb3.0

                Thanks a lot

                martin

                • 5. Re: EJB3 - how to work with lazy loading
                  martinganserer

                  Hello,

                  do you have a fad-client (e.g. Swing)? Do you access your business logic via the remote interface?

                  • 6. Re: EJB3 - how to work with lazy loading
                    heinrich

                    Yes i do. I have Swing client.

                    I fugured out a second issue i'm running in.
                    When this what you have explained above is working, and i have tranfered my lightValue object, how do i access the foreignkey id? The for the relation there is a field with the object of the related table.
                    If i fetch the id from this table, the whole row is read from the database and i have the same overhead as when i am fethcing the complete dependency of one table row.

                    • 7. Re: EJB3 - how to work with lazy loading
                      martinganserer

                      Hello,

                      I must admit that I don't really understand what you are talking about.
                      Maybe we can discuss that point out of this forum?

                      If you want I can give you my mail address or phone number?

                      • 8. Re: EJB3 - how to work with lazy loading
                        heinrich

                        That would be great.
                        I must admid, that this is very confusing.

                        • 9. Re: EJB3 - how to work with lazy loading
                          heinrich

                          hmm, pm is not working here.
                          I'll give you mine
                          jboss@martinheinemann.net

                          • 10. Re: EJB3 - how to work with lazy loading
                            martinganserer

                            Hello,

                            my email address is: martin.ganserer@kontron.com

                            • 11. Re: EJB3 - how to work with lazy loading
                              lipido

                              Is there any solution for this problem. (lazyloading exceptions in remote clients)

                              What is the ellegant/pattern-based/well-known... solution to deal with Lazy Loading from remote clientes.

                              1) Should I say to my clients (swing apps) that they must not call the lazy methods (say getLineItems() ) and use instead a Session method (say getLineItems(Order)).??

                              2) Should I create one ValueObject for every Entity and pass it to clients with only get/set methods to plain fields with no method to get lazy relationships to avoid that calls explained in point 1)

                              3) If I use ValueObject pattern, I loose the advantage of POJO-Based persistence in EJB3 since I can't use the Entities to send it in/out of the physical layer where they are persisted.

                              • 12. Re: EJB3 - how to work with lazy loading
                                patrick_ibg

                                 


                                3) If I use ValueObject pattern, I loose the advantage of POJO-Based persistence in EJB3 since I can't use the Entities to send it in/out of the physical layer where they are persisted.


                                Yes you can... that's the whole advantage of using POJO-based persistence. Your Entity class can be the same as your ValueObject class.

                                On your server, just pre-get all the lazy relations that your client may want to access. You might want to do this smartly via introspection and clone your entity objects. (Be careful, as Hibernate does some funky byte-code enhancements on managed Entities.) Then you can pass that entire object graph back.



                                • 13. Re: EJB3 - how to work with lazy loading

                                  Even if the lazy relations are defined into the CASCADE of relations , you can use specific QUERIES (lets say in DAO session bean) to grab in one shot the needed depth

                                  see JOIN FETCH into the EJB documentation

                                  "4.4.5.3 Fetch Joins
                                  An important use case for LEFT JOIN is in enabling the prefetching of related data items as a side effect
                                  of a query. This is accomplished by specifying the LEFT JOIN as a FETCH JOIN.
                                  A FETCH JOIN enables the fetching of an association as a side effect of the execution of a query. A
                                  FETCH JOIN is specified over an entity and its related entities.
                                  The syntax for a fetch join is
                                  fetch_join ::= [ LEFT [OUTER] | INNER ] JOIN FETCH association_path_expression"

                                  • 14. Re: EJB3 - how to work with lazy loading
                                    deepasenthil

                                    I tried the query

                                    list = manager.createQuery(" from ProjectObject u left join fetch u.projectNumber where u.projectNumber = :projectNumber")

                                    .setParameter("projectNumber", projectNumber) .getResultList();

                                    but it is not working

                                    can you help me
                                    thanks