6 Replies Latest reply on May 7, 2008 1:56 PM by Pete Muir

    Manual flush and @PreUpdate method

    Vladimir Kovalyuk Apprentice

      The method annotated as @PreUpdate is called by flush().
      The method persists an instance of B when updating instance of A.
      The problem is in the fact that object B is not persisted at all. It can be persisted by additional call of flush() but it seems to be an incorrect approach.


      What is expected behavior of manual flush in such situation?

        • 1. Re: Manual flush and @PreUpdate method
          Pete Muir Master

          Can you show us what you mean with some code?

          • 2. Re: Manual flush and @PreUpdate method
            Vladimir Kovalyuk Apprentice

            Something like this. I don't have original code at hands.


            @Entity
            @EntityListeners(AListener.class)
            public class A {}
            
            @Entity
            public class B {
                 A a; B(A a) { this.a = a; }
            }
            
            
            public class AListener {
                 @PreUpdate
                 public void preUpdate(AbstractDataObject object){
                      B b = new B(a);
                      BService.instance().persist(b); // BService uses Seam-managed context
                 }
            }
            
            @Stateful
            @Name
            public class AAction implements AInterface {
                 @In EntityManager entityManager;
                 @Override public void action() {
                      A a = new A();
                      entityManager.persist(a);
                      entityManager.flush();
                      // (1) entityManager.flush();
                 }
            }
            



            The code works within conversation context.
            When persistence context has auto flush mode the code works fine.
            When context has manual flush mode, the instance of A is persisted, but instance of B isn't. Even after converation ends.
            When I remove comment (1) the instance of A is persisted by the first call of flush() and the instance of B is persisted by the following call of flush().


            Personally I like the idea of manual flush. But double-flushing is not enough. There is probability that the second listener would persist another object that would left unpersisted. I'd like to make sure that flush() flushed all the changes.

            • 3. Re: Manual flush and @PreUpdate method
              Pete Muir Master

              My reply seems to have vanished :-(


              What you are doing is illegal - see this or the JPA spec - you can't access the EntityManager in a callback.

              • 5. Re: Manual flush and @PreUpdate method
                Vladimir Kovalyuk Apprentice

                Pete, JPA states the following:



                In general, portable applications should not invoke EntityManager or Query operations,
                access other entity instances, or modify relationships in a lifecycle callback method (19)
                [19] The semantics of such operations may be standardized in a future release of this specification.

                So it is not illegal, it is just not recommended. Hibernate can handle it. But Seam can't right now and isn't ready to hadnle due to   incomplete design of manual flush.


                The Seam reference states:



                As the result of a truly stupid and shortsighted decision by certain non-JBoss, non-Sun and non-Sybase
                members of the EJB 3.0 expert group, there is currently no simple, usable and portable way to implement atomic
                conversations using EJB 3.0 persistence. However, Hibernate provides this feature as a vendor extension to
                the FlushModeTypes defined by the specification, and it is our expectation that other vendors will soon provide
                a similar extension.
                Seam lets you specify FlushModeType.MANUAL when beginning a conversation. Currently, this works only when
                Hibernate is the underlying persistence provider, but we plan to support other equivalent vendor extensions.

                From my humble opinion since Seam stated that somebody made stupid decision the Team should have carefully provided COMPLETE implementation of the alternative approach which doesn't contain collisions.
                I'd like to pay your attention to the fact that Seam offers just partial solution.


                PS please fix your site - I never could reply from the first attempt.

                • 6. Re: Manual flush and @PreUpdate method
                  Pete Muir Master

                  Vladimir Kovalyuk wrote on Apr 17, 2008 02:44 PM:


                  Pete, JPA states the following:

                  In general, portable applications should not invoke EntityManager or Query operations,
                  access other entity instances, or modify relationships in a lifecycle callback method (19)
                  [19] The semantics of such operations may be standardized in a future release of this specification.


                  So it is not illegal, it is just not recommended.


                  Ok, not illegal, but just not defined by JPA.



                  Hibernate can handle it.

                  Why does the ref guide then say A callback method must not invoke EntityManager or Query  methods! Can you show me a reference that says this should work?



                  But Seam can't right now and isn't ready to hadnle due to   incomplete design of manual flush.

                  Manual flush mode comes from Hibernate, not Seam. Seam just makes it easier to enable.