views:

251

answers:

2

Hello Guys,

I am completely fresh to both JDO and GAE, and have been struggling to get my data layer to persist any code at all!

The issues I am facing may be very simple, but I just cant seem to find any a way no matter what solution I try.

Firstly the problem: (Slightly simplified, but still contains all the info necessary) My data model is as such:

User:
    (primary key)
    String emailID
    String firstName

Car:
    (primary key)
    User user
    (primary key)
    String registration
    String model

This was the initial datamodel. I implemented a CarPK object to get a composite primary key of the User and the registration. However that ran into a variety of issues. (Which i will save for another time/question)

I then changed the design as such: User: (Unchanged)

Car:
(primary key)
String fauxPK (here fauxPK = user.getEmailID() + SEP + registration)
User user
String registration
String model

This works fine for the user, and it can insert and retrieve user objects. However when i try to insert a Car Object, i get the following error:

"Cannot have a java.lang.String primary key and be a child object"

Found the following helpful link about it:
http://stackoverflow.com/questions/2063467/persist-list-of-objects

Went to the link suggested there, that explains how to create Keys, however they keep talking about "Entity Groups" and "Entity Group Parents". But I cant seem to find any articles or sites that explain what are "Entity Group"s or an "Entity Group Parents"

I could try fiddling around some more to figure out if i can store an object somehow, But I am running sort on patience and also would rather understand and implement than vice versa.

So i would appreciate any docs (even if its huge) that covers all these points, and preferably has some examples that go beyond the very basic data modeling.

And thanks for reading such a long post :)

+3  A: 

I'm afraid you won't like the answer. GAE JDO has to be used a very specific way and is fraught with limitations that you have to observe to use it effectively. Read the docs forwards and backwards. For the issue you are seeing now, you probably need to read this section a couple of times:

http://code.google.com/appengine/docs/java/datastore/relationships.html

GAE JDO has owned and unowned relationships. See the documentation above for examples of owned vs unowned. I believe you want Car and User to have an unowned relationship. Note this revelation in the Google Apps documentation about unowned relationships:

http://code.google.com/appengine/docs/java/datastore/relationships.html#Unowned_Relationships

In addition to owned relationships, the JDO API also provides a facility for managing unowned relationships. The App Engine implementation of JDO does not yet implement this facility, but don't worry, you can still manage these relationships using Key values in place of instances (or Collections of instances) of your model objects.

This essentially means, to use GAE JDO, you should not use a direct reference for an unowned relationship like between the Car and User classes. Rather, you should use indirect references between them, i.e. Car should have a field for the User's key rather than a direct reference to the User itself. Some of the trouble you are having is because GAE JDO cannot deal with how you are modeling this relationship in code.

Asker goes on to say:

Went to the link suggested there, that explains how to create Keys, however they keep talking about "Entity Groups" and "Entity Group Parents". But I cant seem to find any articles or sites that explain what are "Entity Group"s or an "Entity Group Parents"

Entity Group - a graph of objects that were initially persisted together. For example, because Car refers directly to a User, when you persist a given Car instance for the first time, then you would also persist the User instance to which it refers and this Car instance and this User instance would be part of the same entity group. If this User instance was already been persisted, either independently by itself or as part of another Car instance, then this User instance is already in another entity group. "Owned" relationships are supposed to be in the same entity group. Note that GAE JDO transactions can modify only 1 entity group - any more will raise an exception.

Entity Group Parent - a top-level/root ("parent") persisted class. In the above example, when you persist a given Car instance for the first time, you would also persist the User instance it refers to. The Car instance is the entity group parent. An "owned" "child" class like User embeds its parent's (Car's) key within its own (User) key. If you were to pull a Car instance from the database and then attempt to access the User that this Car refers to, then the GAE JDO will use the Car's key to find the corresponding User (because the target User's key has the parent Car's key embedded as part of its own key).

Asker got this error message:

"Cannot have a java.lang.String primary key and be a child object"

Note this statement in the docs:

The child class must have a key field whose type can contain the parent key information: either a Key, or a Key value encoded as a string. See Creating Data: Keys for information on key field types.

This means that "child" classes must use certain types of keys (i.e. keys that are capable of encapsulating their parent's key within the child's key). Long and String are suitable for entity group parents classes, i.e. non-child classes. However, "child" classes must use either Key or Key encoded as String type for their key. The error message indicates that the Car class refers to the User class as if it were an "owned" "child" class, and therefore the User class must use an key type appropriate for a child, but the User class is not using a key type appropriate for a child (non-encoded String).

The fix for the immediate problem at hand is to model Car and User to be an unowned relationship by changing Car from having the direct reference to User to instead having an indirect reference by storing the related User's key. The overall fix will likely include taking a hard look at how to fit your object model into GAE JDO's framework (once you wade through the docs to try to understand it). This will likely include having to manually manage some of the relationships between the classes.

If its any consolation, I'm dealing with the same sort of issues with GAE JDO myself (I even have a Car class too!).

Bert F
Firstly Thanks for taking the time to provide such a detailed answer!!! Much appreciated...I had initially tried to model owned relationships but that wasnt working due to various problems with the key. Since I am running out of time, and this project is not going to be too much about the DB model, I have decided to go with the indirect references.Will return to experimentation for my next project.
Basil Dsouza
@Basil - I think you wanted an "unowned" relationship, but you coded an "owned" relationship (by using direct references). As indicated in this answer, witching to indirect references is the valid fix - no need to "experiment" further.
Bert F
@Bert: Actually from the start I wanted an Owned Relationship. I had even made the PK objects to represent the User and Car registration as a Key. However that didnt work, with even more confusing problems.For now the fix is acceptable, but I was still interested in learning the right way of doing it as well. Cause the current fix is treating Big Table like a RDBMS.
Basil Dsouza
@Basil - I gotcha. I was thinking that Users and Cars can exist independent of each other, so therefore they have an "unowned" relationship between each other. However, if one doesn't exist without the other in your app/domain, then I get it. Its too bad there are so many restrictions how to model relationships in GAE JDO - it keeps from expressing them easily and intuitively. I'm sure it gets easier as you get used to it.
Bert F