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 google-appeng...@googlegroups.com. To unsubscribe from this group, send email to google-appengine+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/google-appengine?hl=.