1 2 Previous Next 16 Replies Latest reply on Jul 25, 2006 1:11 AM by baz

    @Begin and @End

    bluetrade

      Hi ,

      I have a question regardint conversation propagation. I am passing around a User throughout the application but I don't know how much information of the user I really need. Now, the user might reference to more than 100 other objects, and I don't want to do an eager retrieval of the data, since maybe only 2 objects are needed.
      So right now I use a @Begin(join=true) on almost every page and have the @End tag only when the user enters the logOut method. I can see how this can be problamatic, but what solutions are there if I don't want to run into LIEs (lazy init...)?

      Does anyone have any hints on this? Can I maybe optimize this somehow?

      Thanks
      Joey

        • 1. Re: @Begin and @End
          gavin.king

          If you really _have_ to have transparent lazy fetching of data off of the user, combined with caching of that data then create a session-scoped managed persistence context.

          There are a couple of ways to do this, but the easiest is to use Seam 1.1 CVS build and throw the following in components.xml:

          <component name="userDatabase"
           scope="session"
           class="org.jboss.seam.core.ManagedPersistenceContext">
           <property name="persistenceUnitJndiName">java:/myEntityManagerFactory</property>
          </component>


          Alternatively, an approach I prefer is to only store the userId in session scope, and create an event-scoped manager component for the actual User, that pulls the User out of the (conversation-scoped) persistence context, ie:

          @Scope(EVENT)
          @Name("user")
          public class ManagedUser
          {
           @In(create=true)
           private EntityManager myDatabase;
          
           @In String userId;
          
           @Unwrap
           public User getUser()
           {
           return myDatabase.find(User.class, userId);
           }
          }


          Now, of course you won't get caching of the 100 dependent objects in the session scope, but they do at least get cached in the conversation scope. You will never experience LIEs, as long as you always refer to the dependent objects by injecting the User and then navigating.

          • 2. Re: @Begin and @End
            gavin.king

            P.S. Note that it is never OK to have a conversation that spans an entire login session.

            • 3. Re: @Begin and @End
              gavin.king

              P.P.S. I've seen a couple of people ask about this - would someone please be so kind as to write these solutions up for the Wiki?

              Thanks

              • 4. Re: @Begin and @End
                gavin.king

                Note: I just updated the post to reflect that the manager component need only be EVENT scoped, not CONVERSATION-scoped as I originally wrote.

                • 5. Re: @Begin and @End
                  gavin.king

                  Hmmmmm, I just created a generic ManagedEntity component. Kinda cool, possibly useful. You use it like this:

                  <component name="user"
                   class="org.jboss.seam.core.ManagedEntity">
                   <property name="entityClass">com.myapp.User</property>
                   <property name="entityManager">#{myEntityManager}</property>
                   <property name="id">#{userId}</property>
                  </component>


                  Or even like this:

                  <component name="blogEntry"
                   class="org.jboss.seam.core.ManagedEntity">
                   <property name="entityClass">com.myapp.BlogEntry</property>
                   <property name="entityManager">#{myEntityManager}</property>
                   <property name="id">#{params['blogEntryId']}</property>
                  </component>


                  And then, whenever the id of the object is available in a context variable or request parameter, we can just inject the correct instance.

                  Kinda cool, I think....

                  • 6. Re: @Begin and @End
                    bluetrade

                    Hi Gavin,
                    thanks for your help. Just one last question, is it ok to still keep the user in every (I need it in almost every bean) around via @In @Out User user - I will always then have an @End around the "last"-logic steps...

                    Is there a way to "profile"/"monitor" a seam application to see directly what is in memory and how the transactions are handled? That would be useful for me to understand the whole scenario...

                    THANK YOU SOOO MUCH GAVIN!!!! Seam is great

                    Joey

                    • 7. Re: @Begin and @End
                      gavin.king

                       

                      is it ok to still keep the user in every (I need it in almost every bean) around via @In @Out User user


                      I don't quite understand. With this mechanism you never need @Out. You can do @In(create=true) User user as much as you like.

                      Is there a way to "profile"/"monitor" a seam application to see directly what is in memory and how the transactions are handled? That would be useful for me to understand the whole scenario...


                      There is the Seam debug page, but that does not tell you anything about transactions...

                      • 8. Re: @Begin and @End
                        bluetrade

                        Thanks,
                        sorry, of course Out won't be used...

                        Joey

                        • 9. Re: @Begin and @End

                           

                          "gavin.king@jboss.com" wrote:
                          If you really _have_ to have transparent lazy fetching of data off of the user, combined with caching of that data then create a session-scoped managed persistence context.

                          There are a couple of ways to do this, but the easiest is to use Seam 1.1 CVS build and throw the following in components.xml:

                          <component name="userDatabase"
                           scope="session"
                           class="org.jboss.seam.core.ManagedPersistenceContext">
                           <property name="persistenceUnitJndiName">java:/myEntityManagerFactory</property>
                          </component>
                          


                          Hello, i want to use the approache mentionend above but i have some questions regarding this.

                          1)
                          What does "myEntityManagerFactory" means in this context, is that the value of the "jboss.entity.manager.factory.jndi.name" property described in my persistence.xml ?

                          <property name="persistenceUnitJndiName">java:/myEntityManagerFactory</property>
                          


                          2) how can i use this(java side)?

                          Should i use

                          @PersistenceContext
                          private EntityManager em;

                          or (adepting your example nr1)

                          @In(create=true)
                          private EntityManager userDatabase;


                          Thank u very much,

                          Holger


                          • 10. Re: @Begin and @End
                            baz

                             

                            And then, whenever the id of the object is available in a context variable or request parameter, we can just inject the correct instance.

                            Hi Gavin,
                            i have tried your approach with a ManagedHibernateEntity.
                            i must learn what the word 'whenever' means:
                            if the id is not available i get an exception
                            11:03:13,156 DEBUG org.jboss.seam.Component: instantiating Seam component: bazProject
                            11:03:13,156 DEBUG org.jboss.seam.Component: initializing new instance of: bazProject
                            11:03:13,218 DEBUG org.jboss.seam.Component: seam component not found: bazProjectID
                            11:03:13,234 DEBUG org.hibernate.jdbc.JDBCContext: successfully registered Synchronization
                            java.lang.IllegalArgumentException: id to load is required for loading
                             at org.hibernate.event.LoadEvent.<init>(LoadEvent.java:51)
                             at org.hibernate.event.LoadEvent.<init>(LoadEvent.java:33)
                             at org.hibernate.impl.SessionImpl.get(SessionImpl.java:796)
                             at org.hibernate.impl.SessionImpl.get(SessionImpl.java:792)
                             at org.jboss.seam.core.ManagedHibernateEntity.getInstance(ManagedHibernateEntity.java:52)
                            

                            Does it make sense to you to write getInstance in this way?
                            @Unwrap
                             public Object getInstance() throws ClassNotFoundException
                             {
                             Class clazz = Class.forName(entityClass);
                             if (id==null) return null;
                             return session.get(clazz, id);
                             }
                            

                            Ciao,
                            Carsten

                            • 11. Re: @Begin and @End
                              gavin.king

                               

                              What does "myEntityManagerFactory" means in this context, is that the value of the "jboss.entity.manager.factory.jndi.name" property described in my persistence.xml ?


                              Yes, ofcourse.

                              2) how can i use this(java side)?


                              @In(create=true)
                              private EntityManager userDatabase;


                              • 12. Re: @Begin and @End
                                gavin.king

                                 

                                "baz" wrote:

                                Does it make sense to you to write getInstance in this way?
                                @Unwrap
                                 public Object getInstance() throws ClassNotFoundException
                                 {
                                 Class clazz = Class.forName(entityClass);
                                 if (id==null) return null;
                                 return session.get(clazz, id);
                                 }
                                



                                mmmmmm, do you really need it to work like that?

                                It makes it unclear what "null" means ... does null mean "no id", or does it mean "no object for the id".

                                • 13. Re: @Begin and @End
                                  baz

                                  Hello Gavin.

                                  It makes it unclear what "null" means ... does null mean "no id", or does it mean "no object for the id".

                                  When getInstance is called and there is no Id in any context, session.get is not callable. So the if statement should ensure the pre condition for session.get.

                                  My object which i want to manage is choosen by the user. When the user select the object i set the Id in the appropriate context.
                                  In my app i do not know when a user has the selected the object. So it is possible that i reference this object when no id is set.

                                  Concrete: On each of my pages i have to display the project number of the bazProject the user works on. But as long as the user has not choosen a project, the bazProjectID id will be null.
                                  Ciao,
                                  Carsten




                                  • 14. Re: @Begin and @End
                                    baz

                                    Hi Gavin,
                                    i will change back to my own manager, if you have the opinion that my change does not make sense.
                                    IMHO, it can always happen that 'getInstance()' from the Manager is called when there is no Id in any context. This will result in an exception. But if there is no Id than there is no object. And this must not be an error.
                                    Ciao,
                                    Carsten

                                    1 2 Previous Next