OpenJPA
  1. OpenJPA
  2. OPENJPA-2051

Entities in a relationship are not properly cascaded after a EntityManager.flush is executed.

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Minor Minor
    • Resolution: Fixed
    • Affects Version/s: 2.0.0, 2.1.1, 2.2.0
    • Fix Version/s: 1.2.3, 2.0.2, 2.1.2, 2.2.0
    • Component/s: None
    • Labels:
      None

      Description

      I've found a scenario where upon transaction commit, certain entities which should be persisted via a cascade operation are not present in the database. To properly describe this issue, let me start by first introducing a few entities, and then list a snippet of a test which uses these entities to recreate an issue with cascading entities. That said, take the following three entities:

      public class Vertex {

      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      private long oid;

      @OneToMany(mappedBy = "source", cascade = CascadeType.ALL)
      private List<Edge> outgoing;

      @OneToMany(mappedBy = "target", cascade = CascadeType.ALL)
      private List<Edge> incoming;

      @ManyToOne(cascade = CascadeType.ALL)
      @JoinColumn(name = "TYPE_OID")
      private VertexType type;

      public Edge newEdge( Vertex target )

      { Edge t = new Edge( this ); outgoing.add( t ); t.setTarget( target ); return t; }

      .........

      public class VertexType {

      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      private long oid;

      @OneToMany(mappedBy = "type", cascade = CascadeType.ALL)
      List<Vertex> instances;

      private String name;
      .........

      public class Edge {

      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      private long oid;

      @ManyToOne(cascade = CascadeType.ALL)
      @JoinColumn(name = "SOURCE_OID")
      private Vertex source;

      @ManyToOne(cascade = CascadeType.ALL)
      @JoinColumn(name = "TARGET_OID")
      private Vertex target;
      .........

      Before describing the test case, let me point out a couple important things about these entities. First you will notice that each entity contains a generated id. Second, notice that there are multiple relationships between these entities.

      Now let me introduce the test:

      EntityManager em = emf.createEntityManager();
      EntityTransaction tx = em.getTransaction();

      tx.begin();
      em.flush();

      VertexType defaultType = new VertexType( "default" );
      VertexType specialType = new VertexType( "special" );

      em.persist(defaultType);
      em.persist(specialType);

      Vertex src = new Vertex( defaultType );
      Vertex target = new Vertex( specialType );

      Edge t = src.newEdge( target );
      assertNotNull( t );

      em.persist(src);
      tx.commit();

      Notice that one of the first things the test does is to perform a flush. This may seem slightly odd, however this flush is important to cause the issue. We could execute a query or some other operation which would cause a flush under the covers, however, calling a flush directly makes it clear that a flush has occurred when looking at the rest of the test.

      With the entities and test case in place, let me now describe the issue. After this test case executes, there should exist in the database two Vertex, two VertexType, and one Edge given the cascade type defined in the entities. However, I find that one of the Vertex is missing.

      In working with Rick Curtis on this issue, he found that the 'flush' at the beginning of the test had an effect on the cascade persist at the end of the test. That is, when 'flush' is called, this causes the '_flags' variable in BrokerImpl to be set to flushed as follows:

      _flags |= FLAG_FLUSHED;

      This of course effects the return value of the method BrokerImpl.hasFlushed:

      private boolean hasFlushed()

      { return (_flags & FLAG_FLUSHED) != 0; }

      I will now describe how the return value of this method effects the outcome of the test. However, in an effort of time I am going to skip over some details which I'll leave as an exercise for the reader to figure out (e.g. execute the test in a debugger). Basically this has an effect on SingleFieldManager.persist when called by StateManagerImpl.cascadePersist. That is, SingleFieldManager.persist makes a call to method 'isDetached' on the broker here:

      case JavaTypes.PC_UNTYPED:
      if (!_broker.isDetachedNew() && _broker.isDetached(objval))
      return; // allow but ignore
      _broker.persist(objval, true, call);
      break;

      Code within 'isDetached' eventually makes a call to 'hasFlushed'. Given that 'hasFlushed' returns true, it ultimately effects the result of 'isDetached' and thus causing the persist method in the previously posted code block to be skipped. Again, I'm glossing over some details, but the code path described is also affected by the fact that the ids in these entities are auto generated.

      In order to resolve this problem, we feel the best solution is to change the '_flags' variable to indicate a flush has not occurred. To that end, we propose adding the assignment '_flags &= ~FLAG_FLUSHED'
      to this portion of code in BrokerImpl.setStateManager:

      case STATUS_INIT:
      _flags &= ~FLAG_FLUSHED;
      _cache.add(sm);
      break;

      In addition, this new assignment will be gated by a compatibility property.

      I've included a test patch, named 'CascadePersistIssue.test.patch' which replicates the issue.

        Issue Links

          Activity

          Transition Time In Source Status Execution Times Last Executer Last Execution Date
          Open Open Resolved Resolved
          140d 19h 43m 1 Heath Thomann 03/Feb/12 16:56
          Closed Closed Reopened Reopened
          119d 50m 1 Heath Thomann 01/Jun/12 18:46
          Reopened Reopened Resolved Resolved
          49s 1 Heath Thomann 01/Jun/12 18:47
          Resolved Resolved Closed Closed
          41s 2 Heath Thomann 01/Jun/12 18:47
          Hide
          Heath Thomann added a comment -

          Note that prior to 2.2.1.x/2.2.x, the code of this fix is enabled with the following system property:

          <property name="openjpa.Compatibility" value="resetFlushFlagForCascadePersist=true"/>

          Thanks,

          Heath

          Show
          Heath Thomann added a comment - Note that prior to 2.2.1.x/2.2.x, the code of this fix is enabled with the following system property: <property name="openjpa.Compatibility" value="resetFlushFlagForCascadePersist=true"/> Thanks, Heath
          Heath Thomann made changes -
          Status Resolved [ 5 ] Closed [ 6 ]
          Heath Thomann made changes -
          Status Reopened [ 4 ] Resolved [ 5 ]
          Fix Version/s 1.2.3 [ 12314517 ]
          Fix Version/s 2.1.2 [ 12317142 ]
          Resolution Fixed [ 1 ]
          Heath Thomann made changes -
          Resolution Fixed [ 1 ]
          Status Closed [ 6 ] Reopened [ 4 ]
          Heath Thomann made changes -
          Status Resolved [ 5 ] Closed [ 6 ]
          Heath Thomann made changes -
          Status Open [ 1 ] Resolved [ 5 ]
          Fix Version/s 2.0.2 [ 12315257 ]
          Fix Version/s 2.2.0 [ 12315910 ]
          Resolution Fixed [ 1 ]
          Rick Curtis made changes -
          Affects Version/s 2.1.1 [ 12316191 ]
          Affects Version/s 2.2.0 [ 12315910 ]
          Rick Curtis made changes -
          Link This issue is related to OPENJPA-2107 [ OPENJPA-2107 ]
          Heath Thomann made changes -
          Field Original Value New Value
          Attachment CascadePersistIssue.test.patch [ 12494695 ]
          Hide
          Heath Thomann added a comment -

          Attaching a test case which replicates the issue described.

          Show
          Heath Thomann added a comment - Attaching a test case which replicates the issue described.
          Heath Thomann created issue -

            People

            • Assignee:
              Heath Thomann
              Reporter:
              Heath Thomann
            • Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development