Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[eclipselink-users] Caching problem? when persisting a ManyToOne entity

Bin class has a bidirectional OneToMany relationship with Part class.
  1) A new Part is added to an existing Bin, (also setting its Bin pointer)
and persisted<br/>
  2) The new Part appears in the list (and appears in a separate DB
check)<br/>
  3) The Bin is re-fetched from the DB (cache?) and the Part no longer
appears<br/>
  4) The container is restarted and the Part again appears in the Bins list
This is a JSF Web application produced on NetBeans with Glassfish
I have duplicated this problem using (3-year old?) NetBeans 6.8 and current
Netbeans 7.2
7,2 reports: "EclipseLink, version: Eclipse Persistence Services -
2.3.2.v20111125-r10461"

A workaround appears in comments in the Facade file, but I would rather not
have to visit
the Controller and Facade for the Bin every time a Part is created. I saw a
post by jamesssss
which seemed to say that when merging(or persisting?) objects into the
cache, any relationships in
the object will also be merged into the cache. Does anyone here know what is
happening here?
Thank you in advance for any light someone can shed on this.

The following simplified but complete code demonstrates the problem:

====== Bin class ======
/* Bin.java - Created on Aug 6, 2012, 4:23:22 PM */
package test;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;

@Entity
public class Bin {
    @Id
    private Long id;
    public Long getId()         {   return id;  }
    public void setId(Long id)  {   this.id = id;  }

    @OneToMany(mappedBy="bin", cascade=CascadeType.ALL)
    private List<Part> partsList;

    public List<Part> getPartsList()
    {   return partsList;  }
    public void addPartComplete(Part part)
    {   partsList.add(part);
        part.setBin(this);
    }
    public void addPartSimple(Part part)
    {   partsList.add(part);
    }
}

====== Part class ======
/* Part.java - Created on Aug 6, 2012, 4:26:39 PM */
package test;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

@Entity
public class Part {
    @Id
    private Long id;
    public Long getId()         {   return id;  }
    public void setId(Long id)  {   this.id = id;  }

    @ManyToOne
    private Bin bin;

    public Bin getBin()
    {   return bin;  }
    public void setBin(Bin bin)
    {   this.bin = bin;  }
}

====== Combined Facade for both Entities ======
/* BinPartTestFacade.java - Created on Aug 6, 2012, 4:39:09 PM */
package test;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless
public class BinPartTestFacade {
    @PersistenceContext(unitName = "HomeFoodWebAppPU")
    private EntityManager em;

    public void createBin(Bin bin)
    {   em.persist(bin);  }

    public Bin findBinById(Object id)
    {   return em.find(Bin.class, id);  }

    public void createPart(Part part)
    {   em.persist(part);  }

// **Replacing the createPart() call above with the following code works
around the problem
//    public void createPart(Part part)
//    {   Bin bin = part.getBin();
//        if (bin != null)
//        {   if (!bin.getPartsList().contains(part))
//            {   // moving the adds to AFTER the merge dropped an SQL
queried rebuild of the part list
//                em.merge(bin).getPartsList().add(part);
//                bin.getPartsList().add(part);       // adds to current
in-use bin
//            }
//        }
//        em.persist(part);
//    }

    public Part findPartById(Object id)
    {   return em.find(Part.class, id);  }

    public boolean isManaged(Object entity)
    {   return em.contains(entity);  }
}

====== Combined Controller for both Entities ======
/* BinPartTestController.java - Created on Aug 6, 2012, 4:39:41 PM */
package test;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean(name="binPartTestController")
@SessionScoped
public class BinPartTestController {
    @EJB private test.BinPartTestFacade ejbFacade;

    public BinPartTestController()
    {}

    public String test()
    {
        Bin bin = ejbFacade.findBinById(1L);
        int startCount = bin.getPartsList().size();

        Part part = new Part();
        Long newPartId = 11L + startCount;
        part.setId(newPartId);
        bin.addPartComplete(part);      //also does part.setBin(bin);
        ejbFacade.createPart(part);
        int postAddCount = bin.getPartsList().size();

        bin = ejbFacade.findBinById(1L);
        int refoundBinCount = bin.getPartsList().size();

        return "test results:" +
                        "<br/>Starting Parts List Count = " + startCount +
                        "<br/> => Count After adding New Part =" +
postAddCount +
                        "<br/> => Count after re-querying Bin" +
refoundBinCount;
    }
}

====== JSF page to launch and display results (binPartTest.xhtml) ======

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot;
&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;>
<html xmlns="http://www.w3.org/1999/xhtml";
      xmlns:h="http://java.sun.com/jsf/html";>
    <h:head>
        <title>Bin-Part Test 1</title>
    </h:head>
    <h:body>
        A minimalised demonstration of the @OneToMany problem<br/>
        1) A new Part is added to an existing Bin, (also setting its Bin
pointer) and persisted<br/>
        2) The new Part appears in the list (and appears in a separate DB
check)<br/>
        3) The Bin is re-fetched from the DB (cache?) and the Part no longer
appears<br/>
        4) The container is restarted and the Part again appears in the Bins
list<br/>
        5) Note that restarting the browser (new session?) did NOT make the
Part reappear<br/>
        <br/>
        <h:form>
            <h:outputText value="#{binPartTestController.test()}"
escape="false"/>
        </h:form>
    </h:body>
</html>




--
View this message in context: http://eclipse.1072660.n5.nabble.com/Caching-problem-when-persisting-a-ManyToOne-entity-tp154123.html
Sent from the EclipseLink - Users mailing list archive at Nabble.com.


Back to the top