2 Replies Latest reply on Mar 10, 2010 4:23 PM by Martin Kahres

    tranaction problem

    Martin Kahres Newbie

      Hello,


      I have a problem with a tranaction.


      I have a long runnin conversation. Whenever I get into this conversation and edit an AperakValidierungFeld, it only works for the first time. The second time, I get this stack trace:


      Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.rwe.pokos.entity.validation.AperakValidierungFeld#259]
              at org.hibernate.event.def.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:261)
              at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:120)
              at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:53)
              at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:677)
              at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:661)
              at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:665)
              at org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:227)
              ... 128 more


      So I think the transaction from the first time is still active. But I don't understand why. The method I call is this one:



              public String saveCurrentFeld()
              {
                      String lResult;

                      this.update();

                      Long lID = this.currentFeld.getId();

                      InvalidValue[] lMessages;

                      ClassValidator<AperakValidierungFeld> lValidator =
                              new ClassValidator<AperakValidierungFeld>(AperakValidierungFeld.class);
                      lMessages = lValidator.getInvalidValues(this.currentFeld);

                      int lCount = (lMessages != null ? lMessages.length : 0);
                      if (lCount <= 0)
                      {
                              if(!this.currentFormat.getFelder().contains(this.currentFeld))
                              {
                                      this.currentFeld.setNachrichtenformat(this.currentFormat);
                                      this.currentFormat.addFeld(this.currentFeld);
                              }

                              for(AperakValidierungInhalt inhalt: this.currentFeld.getInhalte())
                              {
                                      inhalt.setFeld(this.currentFeld);
                                      if(inhalt.getId() == null)
                                      {
                                              this.entityManager.persist(inhalt);
                                      }
                                      else
                                      {
                                              inhalt = this.entityManager.merge(inhalt);
                                      }
                              }

                              if (lID == null)
                              {
                                      this.entityManager.persist(this.currentFeld);
                              }
                              else
                              {
                                      this.currentFeld = this.entityManager.merge(this.currentFeld);
                              }

                              lResult = "savedFeld";

                              this.currentFeldId = null;
                      }
                      else
                      {
                              this.showErrors(lMessages);
                              lResult = null;
                      }
                      return lResult;
              }


      It is in a Bean with this annotations:
      @Scope(ScopeType.CONVERSATION)
      @Stateful


      The @TransactionAttribute should be default by REQUIRED. I tried to change there a lot, but nothing really helped.


      In the saveCurrentFeld-method I have this.update() at the beginning. If I delete this, I can't edit a AperakValidierungFeld by the first time. With the update it works one time and then the exception is thrown. My understanding was, that the transaction should start and commit/stop within this method because of the @TransactionAttribute-setting. This is the only method I call in this conversation, so it can't come from another method. In this method I merge also AperakValidierungInhalt-entities. Can it be, that it starts several transactions because of this?


      I also tried to commit the transactions manually, but on a getTransaction call on the entityManager I get this exception:
      javax.ejb.EJBTransactionRolledbackException: JTA EntityManager cannot access a transactions


      I tried also with nested conversation, but didnt help.


      The entity beans have bi-directional many2one and one2many annotations and have @version fields.


      It would be very nice if someone could help me here.


      Thx
      Martin

        • 1. Re: tranaction problem
          Martin Kahres Newbie
          I have read the "15 gotchas in seam" thread point 3 helped me a lot :)

          Do NOT use entityMgr.merge as it gets you into trouble time after time. Use if(bean.getId != null) entityMgr.persist(bean) instead
          • 2. Re: tranaction problem
            Martin Kahres Newbie
            but I think there is a little mistake in the code, it should be like that:

            if(bean.getId == null) entityMgr.persist(bean)

            So I have to persist entities, if they are saved the first time.

            And the second time, seam makes his own updates for this, when I enable @TrasactionAttribute(TransActionAttributeType.REQUIRED)

            Is this right? Maybe this causes the duplicate transactions?