views:

42

answers:

2

I have problem mapping the parent/child relationship in JPA and currently down with the follow error message -

java.lang.IllegalArgumentException: org.datanucleus.exceptions.NucleusException: App Engine ORM does not support multiple parent key provider fields.
 at org.datanucleus.jpa.EntityManagerImpl.find(EntityManagerImpl.java:232)
 at org.datanucleus.store.appengine.jpa.DatastoreEntityManager.find(DatastoreEntityManager.java:56)
 at bios.model.DAO.StudentDAO.retrieveStudent(StudentDAO.java:31)
 at bios.model.manager.StudentMgr.authenticateStudent(StudentMgr.java:27)
 at bios.controller.AuthenticateServlet.doPost(AuthenticateServlet.java:99)
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:713)
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
 at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
 at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:51)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:122)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
 at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
 at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
 at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
 at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
 at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:70)
 at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
 at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:349)
 at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
 at org.mortbay.jetty.Server.handle(Server.java:326)
 at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
 at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:938)
 at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:755)
 at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
 at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
 at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
 at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Caused by: org.datanucleus.exceptions.NucleusException: App Engine ORM does not support multiple parent key provider fields.
 at org.datanucleus.store.appengine.DatastoreTable.markFieldAsParentKeyProvider(DatastoreTable.java:477)
 at org.datanucleus.store.appengine.DatastoreTable.initializeNonPK(DatastoreTable.java:399)
 at org.datanucleus.store.appengine.DatastoreTable.buildMapping(DatastoreTable.java:288)
 at org.datanucleus.store.appengine.DatastoreManager.buildStoreData(DatastoreManager.java:479)
 at org.datanucleus.store.appengine.DatastoreManager.newStoreData(DatastoreManager.java:437)
 at org.datanucleus.store.AbstractStoreManager.addClasses(AbstractStoreManager.java:788)
 at org.datanucleus.store.AbstractStoreManager.addClass(AbstractStoreManager.java:759)
 at org.datanucleus.store.mapped.MappedStoreManager.getDatastoreClass(MappedStoreManager.java:358)
 at org.datanucleus.store.appengine.DatastoreManager.getDatastoreClass(DatastoreManager.java:709)
 at org.datanucleus.store.appengine.DatastoreManager.getDatastoreClass(DatastoreManager.java:87)
 at org.datanucleus.store.appengine.DatastoreTable.initializeNonPK(DatastoreTable.java:393)
 at org.datanucleus.store.appengine.DatastoreTable.buildMapping(DatastoreTable.java:288)
 at org.datanucleus.store.appengine.DatastoreManager.buildStoreData(DatastoreManager.java:479)
 at org.datanucleus.store.appengine.DatastoreManager.newStoreData(DatastoreManager.java:437)
 at org.datanucleus.store.AbstractStoreManager.addClasses(AbstractStoreManager.java:788)
 at org.datanucleus.store.AbstractStoreManager.addClass(AbstractStoreManager.java:759)
 at org.datanucleus.store.mapped.MappedStoreManager.getDatastoreClass(MappedStoreManager.java:358)
 at org.datanucleus.store.appengine.DatastoreManager.getDatastoreClass(DatastoreManager.java:709)
 at org.datanucleus.store.appengine.DatastoreManager.getDatastoreClass(DatastoreManager.java:87)
 at org.datanucleus.store.mapped.mapping.PersistenceCapableMapping.prepareDatastoreMapping(PersistenceCapableMapping.java:198)
 at org.datanucleus.store.mapped.mapping.PersistenceCapableMapping.initialize(PersistenceCapableMapping.java:117)
 at org.datanucleus.store.mapped.mapping.MappingFactory.createMapping(MappingFactory.java:97)
 at org.datanucleus.store.mapped.mapping.AbstractMappingManager.getMapping(AbstractMappingManager.java:248)
 at org.datanucleus.store.appengine.DatastoreTable.initializeNonPK(DatastoreTable.java:322)
 at org.datanucleus.store.appengine.DatastoreTable.buildMapping(DatastoreTable.java:288)
 at org.datanucleus.store.appengine.DatastoreManager.buildStoreData(DatastoreManager.java:479)
 at org.datanucleus.store.appengine.DatastoreManager.newStoreData(DatastoreManager.java:437)
 at org.datanucleus.store.AbstractStoreManager.addClasses(AbstractStoreManager.java:788)
 at org.datanucleus.store.AbstractStoreManager.addClass(AbstractStoreManager.java:759)
 at org.datanucleus.ObjectManagerImpl.newObjectId(ObjectManagerImpl.java:2508)
 at org.datanucleus.jpa.EntityManagerImpl.find(EntityManagerImpl.java:228)
 ... 31 more

Here's my code for Student

@Entity
@Table(name="STUDENT")
public class Student {

    @Id
    @Column(name="userid")
    private String userid;

    @OneToMany(mappedBy = "student", targetEntity = Phone.class,
        fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    private List<Phone> phoneList = new ArrayList<Phone>();

And here's my Phone class.

@Entity
@Table(name="PHONE")
public class Phone {
    @Id
    @Column(name="id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Key id;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name="userid")
    private Student student;

Please help! Thanks! :)

+1  A: 

Just in case, have a look at Issue 1276 (which is invalid). Quoting Max Ross:

As the exception states, on App Engine an Entity cannot have multiple parents. This is because OneToMany is tied to the concept of ancestor in the datastore. Each entity can only have one direct ancestor.

Are you really showing all the code?

Pascal Thivent
Hi Pascal. Thanks for the reply. Here's the full code:
teo
@teo This confirms my answer, an entity cannot have multiple parents on GAE/J. Use sets of keys instead [as documented](http://code.google.com/appengine/docs/java/datastore/relationships.html#Unowned_Relationships) (I write "as documented" but I think the documentation sucks big time).
Pascal Thivent
A: 

//Student entity class @Entity @Table(name="STUDENT") public class Student{

    @Id
    @Column(name="userid")

private String userid;

    @OneToMany(mappedBy = "student",
    targetEntity = Bid.class,
    fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    private List<Phone> phoneList = new ArrayList<Phone>();

    @Basic
    @Column(name="password")

private String password;

    @Basic
    @Column(name="name")

private String name;

    @Basic
    @Column(name="school")

private String school;

//Phone entity class @Entity @Table(name="Phone") public class Phone{

    @Id
    @Column(name="id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Key id;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name="userid")

private Student student;

    @Basic
    @Column(name="number")

private int number;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name="code")

private Course code;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name="section")

private Section section;

teo