3 Replies Latest reply on Dec 4, 2011 8:17 PM by smarlow

    After entityManager.find(), no session or session was closed

    bohl

      This thread continues the discussion in a bug report, see https://issues.jboss.org/browse/AS7-2781

       

      The bug is not closed at the time of writing, so my question depends on whether or how it gets fixed. I will try to describe the problem a bit now, which occurred to me when trying to migrate an application from jboss6 / seam2 to jboss7.

       

      The problem arises when an EntityManager is injected outside an ejb (which is possible in java ee 6), and a entityManager.find() is called outside of a transaction. The retrieved entity appears to be detached right after the find() call, so I get an exception when trying to access one of its "managed" properties (a persistent collection, in this case).

       

      A demo app is attached to this thread (same as in the bug report). The demo app is based on jboss-javaee6-webapp, a maven template that can be checked out using the following command:

       

      mvn org.apache.maven.plugins:maven-archetype-plugin:2.1:generate -DarchetypeGroupId=org.jboss.spec.archetypes -DarchetypeArtifactId=jboss-javaee6-webapp

       

      Is it necessary to start a transaction before making a query, or otherwise you only get detached objects? I've been using EntityManager a lot in java SE (JPA 2 / Hibernate), and it's definitely not necessary. Coming from Seam 2, I would not have expected this (but it may be that seam 2 always keeps a transaction open during the lifetime of a request).

       

      Seems like the JPA 2 spec has a word in this, too (JPA 2.0 specification section 7.6.1).

       

      Also, in case , is there a mechanism which automatically wraps a transaction around every request. What is the best practice?

        • 1. Re: After entityManager.find(), no session or session was closed
          smarlow

          Thanks for reporting this important issue and posting the above information.  It appears that AS6 has a bug, in that the entities are not detached until the business method completes, instead of when the entity manager invocation completes. 

           

          I also rejected AS7-2781 after further discussion and verifying that the entities should be detached when the entity manager (transaction scoped persistence context used with no active jta transaction) returns.  I would like to explore improving this (in a future JPA specification, which IMO would be a good improvement).  No promises on the JPA specification changing, there may be good reasons for the current behaviour that cannot be addressed.  I think that you can follow the JPA 2.1 expert group discussion here, if your interested.

           

          I think that Seam 2 might do some special tricks, to avoid this problem.  I'm not sure how they do that but I think they hook into the persistence provider at a lower level to do the magic.

           

          I assume you don't want to EAGER fetch the collection, otherwise you would of made that change.  EAGER fetch would be one way of fixing this.

           

          I think that you want to make the business method transactional like a session bean would of been (if you used one).  Look for @Transactional here.  Or look at this example of using @Stateful. 

           

          Write back if that helps or doesn't. 

           

          Scott

          • 2. Re: After entityManager.find(), no session or session was closed
            bohl

            Hi Scott, thanks for all these insights. I realized that the kitchensink example you mentioned and the "jboss-javaee6-webapp" maven template I used are pretty much the same application. Now imho there's something wrong with it, since all I did to produce the "no session" exception, was add one lazy-loaded property to the "Member" class in the "kitchensink"-model, and then try to access in MemberListProducer#retrieveAllMembersOrderedByName.

             

            If the kitchensink example is intended to be used as a starting point for new apps (why publish it as a maven template otherwise?), then there should imho at least be a comment indicating that the entities retrieved in MemberListProducer#retrieveAllMembersOrderedByName will get auto-detached. Alternatively, the code could demonstrate how to fetch them "the right way" so that they won't get auto-detached. Because detached entities are usually not what developers expect or want.

            • 3. Re: After entityManager.find(), no session or session was closed
              smarlow

              In KitchenSink, MemberListProducer is not using @Stateful, sorry about the incomplete information.  It looks like MemberRegistration is using @Stateful. 

               

              Rather than reproducing the bug, with KitchenSink, instead just verify that JTA transactions are started MemberListProducer member functions are invoked (you could enable TRACE logging in as7/standalone/configuration/standalone.xml if its not obvious). 

               

              I like your idea for a change to the KitchenSink example.  Maybe that could get added to the section below the code:

              Line Number

              32 - 34 The observer method is notified whenever a member is created, removed, or updated. This allows us to refresh the list of members whenever they are needed. This is a good approach as it allows us to cache the list of members, but keep it up to date at the same time.

               

              Advanced:  Entities loaded without an active JTA transaction, are detached as soon as the EntityManager method returns.  This can cause problems if FetchType.LAZY is used as the lazy fetch will not occur in time.

               

              What happens if you add @Transactional to MemberListProducer#retrieveAllMembersOrderedByName?  Does that succeed in making the member function transactional and your added code in that method succeed in reading the lazy data?

               

              Keep in mind, that enties are detached after the JTA transaction completes, so you probably want to also make the caller to MemberListProducer#retrieveAllMembersOrderedByName @Tranactional  (if the test succeeds).  That way the JTA transaction will start at a higher level (given you more time to read the lazy parts before the entities are detached).