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].
For more options, visit this group at 
http://groups.google.com/group/google-appengine?hl=.


Reply via email to