7 Replies Latest reply on Jan 3, 2008 9:43 AM by lpmon

    EntityManager not auto-flushing at end of SLSB method

    lpmon

      JBoss AS 4.0.5.GA, MySQL, nothing unusual about config, Windows XP

      Examples I have seen suggest that if you modify or create CMP entitybeans inside a session bean method then at the exit of that method these changes will be saved to the DB (flushed without calling em.merge or em.persist). I am not seeing this behavior. I have an app that I did several iterations of the above and the data is never saved.

      Calling em.flush() doesn't work either. If I call em.merge() it works? The merge call works but as documentation suggests that is inefficient. What's the deal?

        • 1. Re: EntityManager not auto-flushing at end of SLSB method
          mazz

          Check your transaction demarcation. Just because you exit a method does NOT automatically mean your entity manager flushes the data to the DB.

          If you exit a method that also exits out of your transaction, THEN it will flush. But if you exit a method that was called with an already started transaction (e.g. tx type== SUPPORTS or an intra-bean call) then it won't necessarily do anything.

          For example, if you call A.method1 which calls A.method2, exiting A.method2 probably won't do anything special (it could, if you want - see REQUIRES_NEW semantics). Exiting A.method1 won't do anything special either, unless the transaction boundary stops at A.method1 (@TransactionType is REQUIRES for example and it was called outside of any tx)

          • 2. Re: EntityManager not auto-flushing at end of SLSB method
            mazz

            Oh, and one other thing. The entity manager will only flush changes that you made to attached POJO entities. You can't just do "new MyEntity()" and expect the entity manager to do anything with it. You must do either em.persist() to attach it as a new entity, an em.find() to load an existing entity into the entity manager session or something similar to load an existing entity into session (like execute a query).

            em.merge() will, by definition, act as a em.persist() if the object you are merging isn't attached and is a new entity that does not yet exist in the DB.

            • 3. Re: EntityManager not auto-flushing at end of SLSB method
              lpmon

              Thanks Mazz.

              I am aware of the transaction layering effect (for lack of a better term) that applies if one session beans calls another. I am certain all of my session bean methods are exiting.
              The code is simple and basic. In this particular method I create one entity and modify another. Neither is saved to the DB unless I call em.merge.

              However, as an experiment, I added this to the method in question:

              @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)

              My understanding of this annotation is that the container should begin a new transaction for this method and it will end when the method exits. Correct? Adding this made no difference. I have never seen any of this work as documentation suggests it should work. I have been using JBoss AS for along time but this is my first EJB3 app. What could I have done wrong to cause this behavior? Again, 4.0.5.GA w/EJB3 (used installer and selected EJB3, Windows XP 64-bit)

              • 4. Re: EntityManager not auto-flushing at end of SLSB method
                mazz

                Perhaps its best if you post your code - what's the method look like in its entirety?

                • 5. Re: EntityManager not auto-flushing at end of SLSB method
                  lpmon

                  I decided to post the code. I just saw your comment about the "new entity ..." and that does explain part of it (purchase not saved ) as you will see. That does not explain why the changed entity (member) did not get saved. Member was injected in the calling SLSB using SEAM and passed to this method.

                  If it is true that a new entity is not saved on exit that needs to be emphasized in documentation. I started with the trailblazer and use the references. Maybe it is in there but I never noticed it.

                  public @Stateless class PurchaseCreditsBean implements PurchaseCredits {

                  @PersistenceContext
                  EntityManager em;

                  @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
                  public void purchaseCredits(Member member, int purchaseQty)
                  {
                  Purchase purchase = new Purchase();
                  purchase.setPurchasedCredits(purchaseQty);
                  member.setCredits(purchaseQty + member.getCredits());

                  purchase.setMember(member);
                  purchase.setPurchasedCredits(purchaseQty);
                  em.merge(purchase); // TODO should not have to call merge
                  em.merge(member);
                  }
                  }

                  Thanks, my assumption is the SEAM injected entity is behaving as if it is not attached to my em as well. If this is the case I certainly misunderstood this. I bet many others have been down this same path!

                  • 6. Re: EntityManager not auto-flushing at end of SLSB method
                    mazz

                    For sure you need to do the merge there (or a em.persist - em.merge is for overwriting data on a possibly existing entity -I suspect you really want to do em.persist here).

                    Just "new MyEntity()" doesn't really do anything - there is no magic here for your entity manager to know that object exists. You need to put it in the JPA session - the only way for that to happen is to load it into the entity manager, either by asking the entity manager to persist/merge it (if it isn't in the DB yet or you want to overwrite it) or to find/load it (if it already exists in the DB) Once the object is "attached" to the entity manager, THEN the magic happens (since its at that point the entity manager knows about your object and can manage it).

                    I don't know much about SEAM, but it sounds like the injected entity POJO isn't attached yet. It sounds like its the same as if you passed in the entity from a remote client (which, it too, would not be attached).

                    If you get passed an entity that you know already exists, to load it into your entity manager:

                    public mySLSBMethod( MyEntity myentity ) {
                    // attach myentity to the entity manager
                    myentity = entityManager.find(MyEntity.class, myentity.getId());

                    I tend to only pass primary keys around, especially for APIs that I want my remote clients to use:

                    public mySLSBMethod( int myentityId ) {
                    MyEntity me = entityManager.find(MyEntity.class, myentityId);

                    That's one way to load it - another way is to load it is via a named query. Once loaded, now anything you do to myentity will be tracked and when the entity manager is flushed, those changes make its way to the DB.

                    • 7. Re: EntityManager not auto-flushing at end of SLSB method
                      lpmon

                      Thanks a bunch Mazz. Very helpful