Thank you for responding. This is not good, but I guess it could be worse. Google could be ignoring these problems instead of fixing them. One more question. What's the right way to install appengine-orm-1.0.4.rc1.zip with the Eclipse App Engine SDK 1.2.6? Do I just replace all the jars in the SDK with the jars from appengine-orm-1.0.4.rc1.zip?
Thanks very much. Rick On Thu, Nov 19, 2009 at 5:03 PM, Ikai L (Google) <[email protected]> wrote: > The current version won't support inheritance, which may explain why this > isn't working. It looks like fixes for inheritance will be going out when > datanucleus is updated: > > http://code.google.com/p/datanucleus-appengine/issues/detail?id=25 > > The stack trace looks different, though, but that may be because you are > using a transaction, and the transaction manager is taking a look at the key > that is being generated and does not recognize "Address" as having > "Customer" as an ancestor. > > I'm not sure why you need a transaction here, though. It doesn't look like > Customer or Address will be out of sync. You could also accomplish the same > thing using an embedded class, though I suppose that wouldn't work if > multiple customers had the same address and addresses changed frequently > (though you could solve this by updating all matching embedded addresses if > an address changes in a transaction, making the Address the parent of the > Customer). > > ---------- Forwarded message ---------- > From: Rick Horowitz <[email protected]> > Date: Thu, Nov 19, 2009 at 1:44 PM > Subject: [google-appengine] Re: Can't get owned relationship working with > JDO and subclass > To: Google App Engine <[email protected]> > > > Does anyone have any idea why this won't work? I've tried every option > I can think of and it still doesn't work. Would really appreciate some > help from someone knowledgeable about JDO and gae. I'm assuming it's > pretty basic to persist a subclass object whose superclass (base > class) references an owned object, but gae doesn't seem to like it. I > tried the base class as abstract and concrete, and tried the keys as > type Key and as encoded String. No luck. > > Thanks very much for any help. > > Rick > > On Nov 15, 11:40 pm, Rick Horowitz <[email protected]> wrote: > > I'm trying to persist a simple class relationship using JDO. My code > > is listed below and here's a brief overview of what I'm trying to do: > > > > I have 3 classes: > > > > Person, Customer (extends Person), and Address (referenced from > > Person). If I create a Person instance and an Address instance and > > call setAddress() on Person, then call > > PersistenceManager.makePersistent(), the objects get saved correctly. > > > > However, if I create a Customer instance and an Address instance, I > > get the following error message: > > > > java.lang.IllegalArgumentException: can't operate on multiple entity > > groups in a single transaction. found both Element { > > type: "Customer" > > id: 1} > > > > and Element { > > type: "Address" > > id: 2 > > > > } > > > > I am doing this from within a JDO transaction. > > > > Here's the code: > > > > First, the server-side code that attempts to create and persist the > > objects: > > > ----------------------------------------------------------------------------------------------------------- > > > > PersistenceManager pm = > PMF.get().getPersistenceManager(); > > Transaction txn = pm.currentTransaction(); > > try { > > txn.begin(); > > Address a = new Address("15 Post Road", "", > "Anytown", "New York", > > "USA", "03801"); > > Customer c = new Customer(); > > c.setAddress(a); > > c.setFirstName("John"); > > c.setLastName("Doe"); > > pm.makePersistent(c); > > txn.commit(); > > } finally { > > if (txn.isActive()) { > > txn.rollback(); > > } > > pm.close(); > > } > > > > Person: > > ----------- > > > > @PersistenceCapable(identityType = IdentityType.APPLICATION) > > @Inheritance(strategy = InheritanceStrategy.SUBCLASS_TABLE) > > public abstract class Person implements Serializable { > > > > public static enum PERSON_KEYS { > > firstName, > > lastName, > > workEmail, > > phoneNbr > > } > > static final long serialVersionUID = 100L; > > > > @PrimaryKey > > @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) > > @Extension(vendorName = "datanucleus", key = "gae.encoded-pk", > > value="true") > > private String key; > > private String firstName; > > private String lastName; > > private String middleInitial; > > private String workEmail; > > private String homeEmail; > > private String phoneNbr; > > @Persistent > > private Address address = new Address(); > > private String salutation; > > > > public Person() { > > } > > > > public String getKey() { > > return key; > > } > > > > public void setKey(String key) { > > this.key = key; > > } > > > > public String getWorkEmail() { > > return (this.workEmail); > > } > > > > public void setWorkEmail(String workEmail) { > > this.workEmail = workEmail; > > } > > > > public String getHomeEmail() { > > return homeEmail; > > } > > > > public void setHomeEmail(String homeEmail) { > > this.homeEmail = homeEmail; > > } > > > > @NotPersistent > > public String getEmailAddress() { > > String emailAddr = getWorkEmail(); > > if ((emailAddr == null) || (emailAddr.length() ==0)) > > emailAddr = getHomeEmail(); > > return emailAddr; > > } > > > > public void setEmailAddress(String emailAddress) { > > setWorkEmail(emailAddress); > > } > > > > @NotPersistent > > public String getFullName() { > > StringBuffer sb = new StringBuffer(); > > if (getFirstName() != null) { > > sb.append(getFirstName()); > > sb.append(" "); > > } > > if ((getMiddleInitial() != null) && > (getMiddleInitial().length() > > > 0)) { > > sb.append(getMiddleInitial()); > > sb.append(" "); > > } > > if (getLastName() != null) { > > sb.append(getLastName()); > > } > > return sb.toString(); > > } > > > > public String getFirstName() { > > return (this.firstName); > > } > > > > public void setFirstName(String firstName) { > > this.firstName = firstName; > > } > > > > public String getLastName() { > > return (this.lastName); > > } > > > > public void setLastName(String lastName) { > > this.lastName = lastName; > > } > > > > public Address getAddress() { > > > > public void setAddress(Address address) { > > this.address = address; > > } > > > > public String getMiddleInitial() { > > return middleInitial; > > } > > > > public void setMiddleInitial(String middleInitial) { > > this.middleInitial = middleInitial; > > } > > > > public String getPhoneNbr() { > > return phoneNbr; > > } > > > > public void setPhoneNbr(String phoneNbr) { > > this.phoneNbr = phoneNbr; > > } > > > > } > > > > Customer: > > --------------- > > > > @PersistenceCapable(identityType = IdentityType.APPLICATION) > > public class Customer extends Person implements Serializable { > > > > static final long serialVersionUID = 100L; > > > > public static enum CUSTOMER_KEYS { > > username, > > password, > > companyName, > > } > > > > public static int FT_STATUS_OK = 0; > > public static int FT_STATUS_ACTIVE_FREE_TRIAL = 1; > > public static int FT_STATUS_ACTIVE_FREE_TRIAL_EXT = 2; > > public static int FT_STATUS_RECENT_FREE_TRIAL = 4; > > public static int FT_STATUS_RECENT_FREE_TRIAL_EXT = 8; > > > > private String username; > > private String password; > > private String companyName; > > private int freeTrialStatus; > > > > public Customer() { > > } > > > > public String getUsername() { > > return (this.username); > > } > > > > public void setUsername(String username) { > > this.username = username; > > } > > > > public String getPassword() { > > return (this.password); > > } > > > > public void setPassword(String password) { > > this.password = password; > > } > > > > public int getFreeTrialStatus() { > > return freeTrialStatus; > > } > > > > public String getCompanyName() { > > return companyName; > > } > > > > public void setCompanyName(String companyName) { > > this.companyName = companyName; > > } > > > > } > > > > Address > > ------------ > > > > @PersistenceCapable(identityType = IdentityType.APPLICATION) > > public class Address implements java.io.Serializable { > > > > static final long serialVersionUID = 100L; > > > > public static enum ADDRESS_KEYS { > > address1, address2, city, state, country, postalCode > > } > > > > @PrimaryKey > > @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) > > @Extension(vendorName = "datanucleus", key = "gae.encoded-pk", > > value="true") > > private String key; > > private Long version; > > private String address1; > > private String address2; > > private String city; > > private String state; > > private String country; > > private String postalCode; > > > > public Address() { > > } > > > > /** > > * Construct the address > > * > > * @param address1 > > * Address line 1 > > * @param address2 > > * Address line 2 > > * @param city > > * The city > > * @param state > > * The state > > * @param country > > * The country > > * @param postalCode > > * Postal/ZIP code > > */ > > public Address(String address1, String address2, String city, > String > > state, > > String country, String postalCode) { > > > > this.address1 = address1; > > this.address2 = address2; > > this.city = city; > > this.state = state; > > this.country = country; > > this.postalCode = postalCode; > > } > > > > public String getKey() { > > return key; > > } > > > > public void setKey(String key) { > > this.key = key; > > } > > > > public Long getVersion() { > > return version; > > } > > > > public void setVersion(Long version) { > > this.version = version; > > } > > > > public void setAddress1(String address1) { > > this.address1 = address1; > > } > > > > public String getAddress1() { > > return this.address1; > > } > > > > public void setAddress2(String address2) { > > this.address2 = address2; > > } > > > > public String getAddress2() { > > return this.address2; > > } > > > > public void setCity(String city) { > > this.city = city; > > } > > > > public String getCity() { > > return this.city; > > } > > > > public void setState(String state) { > > this.state = state; > > } > > > > public String getState() { > > return this.state; > > } > > > > public void setCountry(String country) { > > this.country = country; > > } > > > > public String getCountry() { > > return this.country; > > } > > > > public void setPostalCode(String postalCode) { > > this.postalCode = postalCode; > > } > > > > public String getPostalCode() { > > return this.postalCode; > > } > > > > } > > > > The full stack trace for the exception: > > ------------------------------------------------------ > > > > Caused by: java.lang.IllegalArgumentException: can't operate on > > multiple entity groups in a single transaction. found both Element { > > type: "Customer" > > id: 1} > > > > and Element { > > type: "Address" > > id: 2 > > > > } > > > > at > > com.google.appengine.api.datastore.DatastoreApiHelper.translateError > > (DatastoreApiHelper.java:33) > > at > com.google.appengine.api.datastore.DatastoreApiHelper.makeSyncCall > > (DatastoreApiHelper.java:60) > > at com.google.appengine.api.datastore.DatastoreServiceImpl$2.run > > (DatastoreServiceImpl.java:173) > > at > > com.google.appengine.api.datastore.TransactionRunner.runInTransaction > > (TransactionRunner.java:30) > > at com.google.appengine.api.datastore.DatastoreServiceImpl.put > > (DatastoreServiceImpl.java:161) > > at com.google.appengine.api.datastore.DatastoreServiceImpl.put > > (DatastoreServiceImpl.java:141) > > at com.google.appengine.api.datastore.DatastoreServiceImpl.put > > (DatastoreServiceImpl.java:137) > > at > > > org.datanucleus.store.appengine.RuntimeExceptionWrappingDatastoreService.put > > (RuntimeExceptionWrappingDatastoreService.java:105) > > at > org.datanucleus.store.appengine.DatastorePersistenceHandler.put > > (DatastorePersistenceHandler.java:172) > > at > org.datanucleus.store.appengine.DatastorePersistenceHandler.put > > (DatastorePersistenceHandler.java:112) > > at > > org.datanucleus.store.appengine.DatastorePersistenceHandler.insertObjects > > (DatastorePersistenceHandler.java:239) > > at > > org.datanucleus.store.appengine.DatastorePersistenceHandler.insertObject > > (DatastorePersistenceHandler.java:225) > > at > org.datanucleus.state.JDOStateManagerImpl.internalMakePersistent > > (JDOStateManagerImpl.java:3185) > > at org.datanucleus.state.JDOStateManagerImpl.makePersistent > > (JDOStateManagerImpl.java:3161) > > at org.datanucleus.ObjectManagerImpl.persistObjectInternal > > (ObjectManagerImpl.java:1298) > > at > > > org.datanucleus.store.mapped.mapping.PersistenceCapableMapping.setObjectAsValue > > (PersistenceCapableMapping.java:604) > > at > > org.datanucleus.store.mapped.mapping.PersistenceCapableMapping.setObject > > (PersistenceCapableMapping.java:364) > > at org.datanucleus.store.appengine.DatastoreRelationFieldManager > > $1.setObjectViaMapping(DatastoreRelationFieldManager.java:132) > > at org.datanucleus.store.appengine.DatastoreRelationFieldManager > > $1.apply(DatastoreRelationFieldManager.java:108) > > at > > > org.datanucleus.store.appengine.DatastoreRelationFieldManager.storeRelations > > (DatastoreRelationFieldManager.java:80) > > at > > org.datanucleus.store.appengine.DatastoreFieldManager.storeRelations > > (DatastoreFieldManager.java:795) > > at > > > org.datanucleus.store.appengine.DatastorePersistenceHandler.insertPostProcess > > (DatastorePersistenceHandler.java:288) > > at > > org.datanucleus.store.appengine.DatastorePersistenceHandler.insertObjects > > (DatastorePersistenceHandler.java:241) > > at > > org.datanucleus.store.appengine.DatastorePersistenceHandler.insertObject > > (DatastorePersistenceHandler.java:225) > > at > org.datanucleus.state.JDOStateManagerImpl.internalMakePersistent > > (JDOStateManagerImpl.java:3185) > > at org.datanucleus.state.JDOStateManagerImpl.makePersistent > > (JDOStateManagerImpl.java:3161) > > at org.datanucleus.ObjectManagerImpl.persistObjectInternal > > (ObjectManagerImpl.java:1298) > > at org.datanucleus.ObjectManagerImpl.persistObject > > (ObjectManagerImpl.java:1175) > > at org.datanucleus.jdo.JDOPersistenceManager.jdoMakePersistent > > (JDOPersistenceManager.java:669) > > ... 36 more > > -- > > You received this message because you are subscribed to the Google Groups > "Google App Engine" group. > To post to this group, send email to [email protected]. > To unsubscribe from this group, send email to > [email protected]<google-appengine%[email protected]> > . > For more options, visit this group at > http://groups.google.com/group/google-appengine?hl=. > > > > > > -- > Ikai Lan > Developer Programs Engineer, Google App Engine > > -- > You received this message because you are subscribed to the Google Groups > "Google App Engine" group. > To post to this group, send email to [email protected]. > To unsubscribe from this group, send email to > [email protected]<google-appengine%[email protected]> > . > For more options, visit this group at > http://groups.google.com/group/google-appengine?hl=. > -- You received this message because you are subscribed to the Google Groups "Google App Engine" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/google-appengine?hl=.
