3

I have two models: Author and Book, where an author may have a list of books. To start with Author has a long @id and Book has a string @id.

When I try to put data into the datastore, I get the error Cannot have a java.lang.String primary key and be a child object (owning field …. After searching online, I landed on Persist List of objects. So from there I decided to use, within the Book class,

@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;

and then in the constructor, I do

Key key = KeyFactory.createKey(Book.class.getSimpleName(), bookCode);
this.key = key; // which is the same as calling bookObject.setKey(key)

So now I am getting this new error

class Book has application-identity and no objectid-class specified yet has 0 primary key fields. Unable to use SingleFieldIdentity.

Will someone please provide a code snippet that will rectify this problem? Or at least some specific guidance?

EDIT code:

@Entity
public class Book{
   @PrimaryKey
   @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
   private Key key;

   private String title;

   //other fields

   //getters and setters follow

}

@Entity
public class Author{
   @Id
   private long ssn;

   private String firstName;

   private String lastName;

   List<Book> books;

   //getters and setters follow
}

EDIT ADD STACK TRACE:

java.lang.ExceptionInInitializerError
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:169)
    at com.google.appengine.tools.development.agent.runtime.RuntimeHelper.checkRestricted(RuntimeHelper.java:70)
    at com.google.appengine.tools.development.agent.runtime.Runtime.checkRestricted(Runtime.java:64)
    at com.friends.bookclub.dao.impl.GenericDaoImpl.getEntityManager(GenericDaoImpl.java:82)
    at com.friends.bookclub.dao.impl.GenericDaoImpl.put(GenericDaoImpl.java:45)
    at com.friends.bookclub.BookclubApi.registerUser(BookclubApi.java:76)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.google.appengine.tools.development.agent.runtime.Runtime.invoke(Runtime.java:115)
    at com.google.api.server.spi.SystemService.invokeServiceMethod(SystemService.java:304)
    at com.google.api.server.spi.SystemServiceServlet.execute(SystemServiceServlet.java:161)
    at com.google.api.server.spi.SystemServiceServlet.doPost(SystemServiceServlet.java:120)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    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.socket.dev.DevSocketFilter.doFilter(DevSocketFilter.java:74)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.tools.development.ResponseRewriterFilter.doFilter(ResponseRewriterFilter.java:123)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.tools.development.HeaderVerificationFilter.doFilter(HeaderVerificationFilter.java:34)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:61)
    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:125)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.tools.development.DevAppServerServersFilter.doFilter(DevAppServerServersFilter.java:106)
    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.appengine.tools.development.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:94)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:421)
    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: javax.persistence.PersistenceException: Explicit persistence provider error(s) occurred for "transactions-optional" after trying the following discovered implementations: org.datanucleus.api.jpa.PersistenceProviderImpl from provider: org.datanucleus.api.jpa.PersistenceProviderImpl
    at javax.persistence.Persistence.createPersistenceException(Persistence.java:242)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:184)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:70)
    at com.friends.bookclub.domain.utils.EMF.<clinit>(EMF.java:8)
    ... 50 more
Caused by: org.datanucleus.metadata.InvalidClassMetaDataException: Class com.friends.bookclub.db.Book has application-identity and no objectid-class specified yet has 0 primary key fields. Unable to use SingleFieldIdentity.
    at org.datanucleus.metadata.AbstractClassMetaData.determineObjectIdClass(AbstractClassMetaData.java:1355)
    at org.datanucleus.metadata.ClassMetaData.populate(ClassMetaData.java:209)
    at org.datanucleus.metadata.MetaDataManager$1.run(MetaDataManager.java:2699)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.datanucleus.metadata.MetaDataManager.populateAbstractClassMetaData(MetaDataManager.java:2693)
    at org.datanucleus.metadata.MetaDataManager.populateFileMetaData(MetaDataManager.java:2516)
    at org.datanucleus.metadata.MetaDataManager.initialiseFileMetaDataForUse(MetaDataManager.java:1123)
    at org.datanucleus.metadata.MetaDataManager.loadPersistenceUnit(MetaDataManager.java:986)
    at org.datanucleus.api.jpa.JPAEntityManagerFactory.initialiseNucleusContext(JPAEntityManagerFactory.java:754)
    at org.datanucleus.api.jpa.JPAEntityManagerFactory.initialise(JPAEntityManagerFactory.java:417)
    at org.datanucleus.api.jpa.JPAEntityManagerFactory.<init>(JPAEntityManagerFactory.java:380)
    at org.datanucleus.api.jpa.PersistenceProviderImpl.createEntityManagerFactory(PersistenceProviderImpl.java:91)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:150)
    ... 52 more
Apr 5, 2013 8:54:21 AM com.google.api.server.spi.SystemService invokeServiceMethod
SEVERE: null
java.lang.ExceptionInInitializerError
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:169)
    at com.google.appengine.tools.development.agent.runtime.RuntimeHelper.checkRestricted(RuntimeHelper.java:70)
    at com.google.appengine.tools.development.agent.runtime.Runtime.checkRestricted(Runtime.java:64)
    at com.friends.bookclub.dao.impl.GenericDaoImpl.getEntityManager(GenericDaoImpl.java:82)
    at com.friends.bookclub.dao.impl.GenericDaoImpl.put(GenericDaoImpl.java:45)
    at com.friends.bookclub.BookclubApi.registerUser(BookclubApi.java:76)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.google.appengine.tools.development.agent.runtime.Runtime.invoke(Runtime.java:115)
    at com.google.api.server.spi.SystemService.invokeServiceMethod(SystemService.java:304)
    at com.google.api.server.spi.SystemServiceServlet.execute(SystemServiceServlet.java:161)
    at com.google.api.server.spi.SystemServiceServlet.doPost(SystemServiceServlet.java:120)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    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.socket.dev.DevSocketFilter.doFilter(DevSocketFilter.java:74)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.tools.development.ResponseRewriterFilter.doFilter(ResponseRewriterFilter.java:123)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.tools.development.HeaderVerificationFilter.doFilter(HeaderVerificationFilter.java:34)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:61)
    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:125)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.tools.development.DevAppServerServersFilter.doFilter(DevAppServerServersFilter.java:106)
    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.appengine.tools.development.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:94)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:421)
    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: javax.persistence.PersistenceException: Explicit persistence provider error(s) occurred for "transactions-optional" after trying the following discovered implementations: org.datanucleus.api.jpa.PersistenceProviderImpl from provider: org.datanucleus.api.jpa.PersistenceProviderImpl
    at javax.persistence.Persistence.createPersistenceException(Persistence.java:242)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:184)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:70)
    at com.friends.bookclub.domain.utils.EMF.<clinit>(EMF.java:8)
    ... 50 more
Caused by: org.datanucleus.metadata.InvalidClassMetaDataException: Class com.friends.bookclub.db.Book has application-identity and no objectid-class specified yet has 0 primary key fields. Unable to use SingleFieldIdentity.
    at org.datanucleus.metadata.AbstractClassMetaData.determineObjectIdClass(AbstractClassMetaData.java:1355)
    at org.datanucleus.metadata.ClassMetaData.populate(ClassMetaData.java:209)
    at org.datanucleus.metadata.MetaDataManager$1.run(MetaDataManager.java:2699)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.datanucleus.metadata.MetaDataManager.populateAbstractClassMetaData(MetaDataManager.java:2693)
    at org.datanucleus.metadata.MetaDataManager.populateFileMetaData(MetaDataManager.java:2516)
    at org.datanucleus.metadata.MetaDataManager.initialiseFileMetaDataForUse(MetaDataManager.java:1123)
    at org.datanucleus.metadata.MetaDataManager.loadPersistenceUnit(MetaDataManager.java:986)
    at org.datanucleus.api.jpa.JPAEntityManagerFactory.initialiseNucleusContext(JPAEntityManagerFactory.java:754)
    at org.datanucleus.api.jpa.JPAEntityManagerFactory.initialise(JPAEntityManagerFactory.java:417)
    at org.datanucleus.api.jpa.JPAEntityManagerFactory.<init>(JPAEntityManagerFactory.java:380)
    at org.datanucleus.api.jpa.PersistenceProviderImpl.createEntityManagerFactory(PersistenceProviderImpl.java:91)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:150)
    ... 52 more
Community
  • 1
  • 1
learner
  • 11,490
  • 26
  • 97
  • 169
  • In which line you get the error? And what's the primary key of `Author` class? – MikO Apr 05 '13 at 16:47
  • @MikO I left the stack track out because it was too long. I have now included it. Also the `@id` of author is of type `long` – learner Apr 05 '13 at 17:01

2 Answers2

1

I think the problem is obviously related with the keys of Book and Author.

You may not like my solution and probably is not the best one. As for my (short) experience dealing with owned-relationships in GAE Datastore, I've been getting many errors related with keys, so I ended up doing the following:

I use this as primary keys for ALL my classes:

@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;

And I let the application create the key completely, I mean, I don't try to add any application-created value to the key. I just have getter and setter for the key, but I don't do anything with it in the constructor.

If I want to have my own id/code/key for my objects, I just add antoher attribute in the class.

I know this may be the "coward" solution, but everything is working better for me now...

EDIT: As said before this is not the best approach, because key queries are faster than queries by other fields, so if anyone have a good solution I'd appreciate it as well...

MikO
  • 18,243
  • 12
  • 77
  • 109
  • I think MikO is right, generating a key using a key name can be a pain in the ass and it does not offer much additional value over an indexed attribute. You can just use your book code as an indexed attribute. – Michael Técourt Apr 05 '13 at 17:20
  • 1
    The problem with that approach is that it catches up with you later as appengine is more expensive for queries that do not get by the primary key where possible. – learner Apr 05 '13 at 17:22
  • I implemented as you suggested, but I still get the same error: same stack trace. So maybe I was wrong about the root cause. – learner Apr 05 '13 at 17:42
  • @MichaelakoTecourt as well: Since the root cause may be different than previously thought, I have edited to add the source code. – learner Apr 05 '13 at 17:54
  • You have not implemented it as I suggested... In my approach you must have also in the Author class a key like I described. I don't know if it'll solve the problem, but at least is what I usually do... – MikO Apr 05 '13 at 17:56
0

I don't know if this is still relevant but it will solve the problem in the Author Class -

 private long ssn;

Shoud be

 private Long ssn;
sunny_side_of_life
  • 149
  • 1
  • 3
  • 15