If a Person and a Venue only ever have one Tip then you can re-put them with the parent child relationship you want.

But if I understand what you are trying to do here that is not a correct representation?

On 4 Feb 2010, at 12:25, Wong wrote:


I guess I have to opt for option 1. As the Venue and Person have
already been persisted (e.g. Venue(12087) and Person(1)) before a Tip
is created (posted on a venue by a person). In this case, I have to
use one owned one-to-many relationship (between Venue and Tips) and
one unowned one-to-many relationship using keys (between Person and
Tips).

I think I won't be able to use Tip as root for both Venue and Person
(e.g. Tip(100)/Venue(12087) and Tip(100)/Person(1)) as both Venue and
Person have been persisted as Venue(12087) and Person(1) respectively.
Am I right?




On Feb 3, 10:13 am, "Ikai L (Google)" <ika...@google.com> wrote:
The explanation for the exception is in the exception text itself. Each
entity's key contains the ancestor information for that entity:

http://code.google.com/appengine/articles/storage_breakdown.html

<http://code.google.com/appengine/articles/ storage_breakdown.html>"A path is a concatenation of entity keys. Every path begins with the key of the root entity (which may be the current entity itself) in the current entity group. If the current entity is not the root, then the key of each ancestor is appended to the path, from top to bottom, until the current entity's key is
appended."

That is, if you persist Venue before persisting its parent, you get the key
Venue(ID). Were you to persist the ancestors first, you would get an
unencoded key of Person(PERSON_ID)/TIP(TIP_ID)/Venue(VENUE_ID).

You've got a few options here:

1. Store the Key instead. This won't force the entities into an entity group relationship. The tradeoff here is that you lose the ability to perform
transactions on these entities.

2. Restructure your entity groups. Remember that these are in a tree-like hierarchy with a root entity and child entities. This limits the way you can design one-to-many relationships without using keys, as entities cannot be
part of multiple entity groups. Our docs on this are 
here:http://code.google.com/appengine/docs/java/datastore/relationships.html



On Sun, Jan 31, 2010 at 6:28 AM, Wong <lhw...@gmail.com> wrote:

In my application I have bi-directional one-to-many relationship
between Venue and Tip.

@Entity
public class Venue implements Serializable {
       @Id
       @GeneratedValue(strategy = GenerationType.IDENTITY)
       private Key key;

       @OneToMany(cascade = CascadeType.ALL, mappedBy="venue")

   private List<Tip> tips;

@Entity
public class Tip implements Serializable {
       @Id
       @GeneratedValue(strategy = GenerationType.IDENTITY)
       private Key key;

       private Integer version;

       @ManyToOne(fetch = FetchType.LAZY)
       private Venue venue;

I have venue object persisted and then tip is added to the venue. I
don't any any problem in doing this.

Venue venue = venueService.find(key);
venue.addTip(tip);
venueService.merge(venue);

Then I expand the relationship to have another bi-directional one- to-
many relationship between Person and Tip. Tip is posted by a Person
and for a Venue. One Person can post more than one Tips for a Venue.

@Entity
public class Tip implements Serializable {
       @Id
       @GeneratedValue(strategy = GenerationType.IDENTITY)
       private Key key;

       @ManyToOne(fetch = FetchType.LAZY)
       private Venue venue;

       @ManyToOne(fetch = FetchType.LAZY)
       private Person postedBy;

@Entity
public class Person implements Serializable, UserDetails {
       @Id
       @GeneratedValue(strategy = GenerationType.IDENTITY)
       private Key key;

       @OneToMany(cascade = CascadeType.ALL, mappedBy="postedBy")
       private List<Tip> tips;

Venue venue = venueService.find(key);
Person person = personService.find(userId);
venue.addTip(tip);
person.addTip(tip);
venueService.merge(venue);

I am getting the following error:

Detected attempt to establish Person(29)/Tip(125) as the parent of
Venue(2) but the entity identified by Venue(2) has already been
persisted without a parent. A parent cannot be established or changed
once an object has been persisted.
org.datanucleus.store.appengine.FatalNucleusUserException: Detected
attempt to establish Person(29)/Tip(125) as the parent of Venue(2) but the entity identified by Venue(2) has already been persisted without a
parent. A parent cannot be established or changed once an object has
been persisted. at

org .datanucleus .store.appengine.DatastoreRelationFieldManager.checkForParentSwitch
(DatastoreRelationFieldManager.java:204) at
org.datanucleus.store.appengine.DatastoreRelationFieldManager
$1.setObjectViaMapping(DatastoreRelationFieldManager.java:125) at
org.datanucleus.store.appengine.DatastoreRelationFieldManager $1.apply
(DatastoreRelationFieldManager.java:104) at

org .datanucleus .store.appengine.DatastoreRelationFieldManager.storeRelations
(DatastoreRelationFieldManager.java:78) at
org.datanucleus.store.appengine.DatastoreFieldManager.storeRelations
(DatastoreFieldManager.java:812) 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.flush
(JDOStateManagerImpl.java:4513) at
org.datanucleus.sco.SCOUtils.validateObjectForWriting(SCOUtils.java:
1494) at

org .datanucleus .store .mapped.scostore.ElementContainerStore.validateElementForWriting
(ElementContainerStore.java:380) at
org .datanucleus .store.mapped.scostore.FKListStore.validateElementForWriting
(FKListStore.java:609) at
org.datanucleus.store.mapped.scostore.FKListStore.internalAdd
(FKListStore.java:344) at
org.datanucleus.store.mapped.scostore.AbstractListStore.add
(AbstractListStore.java:105) at org.datanucleus.sco.backed.List.add
(List.java:649) at guestbook.domain.Person.addTip(Person.java:164) at
guestbook.web.mvc.TipController.create(TipController.java:94) at

Any idea? Your help is very much appreciated.

--
You received this message because you are subscribed to the Google Groups
"Google App Engine for Java" group.
To post to this group, send email to
google-appengine-j...@googlegroups.com.
To unsubscribe from this group, send email to
google-appengine-java+unsubscr...@googlegroups.com<google-appengine-java%2bunsubscr...@googlegroups.com >
.
For more options, visit this group at
http://groups.google.com/group/google-appengine-java?hl=en.

--
Ikai Lan
Developer Programs Engineer, Google App Enginehttp://googleappengine.blogspot.com |http://twitter.com/app_engine

--
You received this message because you are subscribed to the Google Groups "Google App Engine for Java" group. To post to this group, send email to google-appengine-java@googlegroups.com . To unsubscribe from this group, send email to google-appengine-java+unsubscr...@googlegroups.com . For more options, visit this group at http://groups.google.com/group/google-appengine-java?hl=en .


--
You received this message because you are subscribed to the Google Groups "Google 
App Engine for Java" group.
To post to this group, send email to google-appengine-j...@googlegroups.com.
To unsubscribe from this group, send email to 
google-appengine-java+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-appengine-java?hl=en.

Reply via email to