OpenJPA
  1. OpenJPA
  2. OPENJPA-286

Can't merge detached One-To-Many child instance. The entities were implement by an internal Hash container.

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 0.9.7, 1.0.0, 1.1.0
    • Fix Version/s: 1.2.0
    • Component/s: jdbc
    • Labels:
      None
    • Environment:
      java version "1.5.0_10"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_10-b03)
      Java HotSpot(TM) Client VM (build 1.5.0_10-b03, mixed mode, sharing)

      Description

      Maybe you know, one of the entity implementation is composite of a hash set, which stores key-value pairs.

      It's a common design of Entity Bean in EJB2.x ages. Does any one use it in OpenJPA? I am using it right now, and encounter an issue in entity cascade manipulate. Here is the issue description.

      Base.java : the super class of entities.
      protected final Object getAttributeValue(String attributeName)

      { return _values.get(attributeName); }

      protected final void setAttributeValue(String attributeName, Object value)

      { _values.put(attributeName, value); }

      // To hold the

      {attributeName, value}

      pair of the value object.
      private HashMap<String, Object> _values = new HashMap<String, Object>();

      C.java extends Base.java : Entity C has a set of Entity D.
      public void setDs(Set<D> ds)

      { setCollection("Ds", ds); }

      @OneToMany(mappedBy = "c", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
      public Set<D> getDs()

      { return (Set<D>)getAttributeValue("Ds"); }

      D.java extends Base.java as well.

      The relationship between C and D is one-to-many. I use following code to reproduce the issue.

      C c = em.find(C.class, 1);
      logger.debug(c.getDs().size());
      D d = new D();
      d.setC(c);
      c.getDs().add(d);
      em.merge(c);

      After commit the transaction, you will find the new D instance was not inserted into the database(there is no insert sql log as well). After you add, em.persist(c). That new instance will be added!

      Meanwhile, I wrote a couple of classes, which do not use a HashSet. I got the expected result after merge is done.

        Activity

        Hide
        Gene Wu added a comment -

        I prepared a test case to reproduce the issue.

        The package path will be "openjpa-persistence-jdbc\src\test\java\org\apache\openjpa\persistence\hashpojo".

        You can feel free to modify them.

        Gene

        Show
        Gene Wu added a comment - I prepared a test case to reproduce the issue. The package path will be "openjpa-persistence-jdbc\src\test\java\org\apache\openjpa\persistence\hashpojo". You can feel free to modify them. Gene
        Hide
        Pinaki Poddar added a comment -

        This style of modeling persistent states as a name-value pair does not notify OpenJPA which field has been dirtied and hence the observed behavior.
        Inform OpenJPA when a field has been dirtied and things should work.
        The added lines in TestMargeHashEntity (around Line 79) are marked with + and additional comments

        em = emf.createEntityManager();
        em.getTransaction().begin();
        + parent = em.merge(parent); // merge the detached entity to the current context
        + OpenJPAPersistence.cast(em).dirty(parent, "children"); // mark it dirty because OpenJPA did not understand that the name-value pair has been updated
        // now proceed as usual by merging it again so that it can detect the new child added in detached state
        parent = em.merge(parent);
        em.getTransaction().commit();
        em.close();

        Show
        Pinaki Poddar added a comment - This style of modeling persistent states as a name-value pair does not notify OpenJPA which field has been dirtied and hence the observed behavior. Inform OpenJPA when a field has been dirtied and things should work. The added lines in TestMargeHashEntity (around Line 79) are marked with + and additional comments em = emf.createEntityManager(); em.getTransaction().begin(); + parent = em.merge(parent); // merge the detached entity to the current context + OpenJPAPersistence.cast(em).dirty(parent, "children"); // mark it dirty because OpenJPA did not understand that the name-value pair has been updated // now proceed as usual by merging it again so that it can detect the new child added in detached state parent = em.merge(parent); em.getTransaction().commit(); em.close();

          People

          • Assignee:
            Pinaki Poddar
            Reporter:
            Gene Wu
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development