GAE Datastore: persistent reference objects

I am trying to migrate Java objects to a GAE data store.

I'm not sure how to save an object having a ("non-trivial") reference object. That is, suppose I have the following.

public class Father { String name; int age; Vector<Child> offsprings; //this is what I call "non-trivial" reference //ctor, getters, setters... } public class Child { String name; int age; Father father; //this is what I call "non-trivial" reference //ctor, getters, setters... } 

The name field is unique in each type of domain and is considered the Primary Key.

To save the "trivial" (String, int) fields, I only need to add the correct annotation. So far, so good. However, I do not understand how I should persist in homes ("Child, father"). Should I:

  • Convert each such link to hold the Primary-Key (the String name in this example) instead of the "actual" object, therefore Vector<Child> offsprings; becomes Vector<String> offspringsNames; ?

    If so, how to do it. I process the object at runtime? Am I just asking for the primary key from Class.getName to get overridden objects?

  • Convert each such link to hold the actual key provided to me by the data store with the correct put() operation? That is, Vector<Child> offsprings; becomes Vector<Key> offspringsHashKeys; ?

I read all the white papers / GAE example. Throughout the entire time, they always retain the “trivial” links supported by this repository (for example, in the Guest Book example, only the Lines and Long lines).

+7
java google-app-engine google-cloud-datastore
source share
3 answers
  • Please check google appengine docs after sections for a clearer understanding (relationships, transactions)

  • Also read about removable objects in JDO

  • To request custom columns (or fields), read about fetchgroups in JDO

For your question, you have several options:

  • Own One-to-Many Relationships (objects will be in the same entity group). Here you can have a list of the Child in your parent (Father class). This will put all the objects in one entity group. If you do not want to receive children every time you send the Father, you can remove children from the "default samples" group

 @PersistenceCapable (identityType = IdentityType.APPLICATION, detachable = "true")
 public class Father {
    @PrimaryKey
    @Persistent
    private String name;

    @Persistent
    private int age;

    @Persistent (mappedBy = "father", defaultFetchGroup = "false")
    private list childern;
 }

 @PersistenceCapable (identityType = IdentityType.APPLICATION, detachable = "true")
 public class Child {
    @Persistent
    @PrimaryKey
    private String name;

    @Persistent
    private Father dad;
 }

  • Canceled relationships in which you store keys instead of links:

 @PersistenceCapable (identityType = IdentityType.APPLICATION, detachable = "true")
 public class Father {

    @PrimaryKey
    @Persistent
    private String name;

    @Persistent
    private int age;

    @Persistent
    private list childern;
 }

 @PersistenceCapable (identityType = IdentityType.APPLICATION, detachable = "true")
 public class Child {
    @Persistent
    @PrimaryKey
    private String name;

    @Persistent
    private Key dad;
 }

In this case, you will have to manage referential integrity, as well as make sure that they are in the same entity group if you need to update / add them in one transaction

IMO, if I were to simulate a real-world scenario (father-children), I would go along the “Own relativism” route, since there really are how many children a guy can have;). Of course, there is still the question of how many fathers are you going to update at the same time?

Hope this helps, cheers!

0
source share

I have examples of creating parent / child relationships using GAE / JPA in my jappstart project. See how authentication related objects relate to each other here .

one-to-one (see UserAccount.java and PersistentUser.java):

 // parent @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) private PersistentUser persistentUser; // child @OneToOne(mappedBy = "persistentUser", fetch = FetchType.LAZY) private UserAccount userAccount; 

One-to-many (see PersistentUser.java):

 @OneToMany(mappedBy = "persistentUser", cascade = CascadeType.ALL) private Collection<PersistentLogin> persistentLogins; 

One-to-one (see PersistentLogin.java):

 @ManyToOne(fetch = FetchType.LAZY) private PersistentUser persistentUser; 

Also pay attention to the constructors, how KeyFactory is used for objects with a parent and without a parent.

 @Id private Key key; // this entity has a parent public PersistentUser(final Key key, final String username) { this.key = KeyFactory.createKey(key, getClass().getSimpleName(), username); ... } // this entity does not have a parent public UserAccount(final String username) { this.key = KeyFactory.createKey(getClass().getSimpleName(), username); .... } 

Hope this helps you. I could not say from the question whether you are using JPA or JDO.

0
source share

If you have a link to Father in Child and Child ren in Father, than you have a chance of inconsistency, assuming that the relationship between Father and Child is two-way (i.e. each father of Child should be in the list of Child ren for this Father ) Only one of two links is required.

Both solutions will work, but keeping the father’s list of children has two drawbacks:

  • Each access to the Father object loads the list keys to the child object. If there are many keys, this can lead to unnecessary overhead.
  • I believe GAE limits the size of the list to 5000 items.
0
source share

All Articles