Has anybody setup an owned Collection in RequestFactory? Does know how to set the ParentKey/ChildKey?

64 views
Skip to first unread message

Brandon Donnelson

unread,
Oct 16, 2011, 9:06:14 PM10/16/11
to google-we...@googlegroups.com

I'd like to use an owned List<entity> collection. I ran out of time this weekend to figure out how to use an Owned Collection in RequestFactory.

Has anybody else used an owned collection in the Entity with RequestFactory?

@PersistenceCapable
@Version(strategy = VersionStrategy.VERSION_NUMBER, extensions = { @Extension(vendorName = "datanucleus", key = "key", value = "version") })
public class WalletData {

@PrimaryKey
 
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
 
private Key key;
 
 
@Persistent
 
private Integer version;
 
 
/**
   * entity owner - the person who's logged in
   */

 
@Persistent
 
private Long userId;
 
 
@Persistent
 
private String name;
 
 
@Persistent(defaultFetchGroup = "true", dependentElement = "true")  
 
private List<WalletItemData> items;
 
 
 
public void setId(Long id) {
   
if (id == null) {
     
return;
   
}
   
this.key = KeyFactory.createKey(UserData.class.getName(), id);
 
}
 
public Long getId() {
   
Long id = null;
   
if (key != null) {
      id
= key.getId();
   
}
   
return id;
 
}
 
 
public void setVersion(Integer version) {
   
this.version = version;
 
}
 
public Integer getVersion() {
   
return version;
 
}
 
 
public void setUserId(Long userId) {
   
this.userId = userId;
 
}
 
public Long getUserId() {
   
return userId;
 
}
 
 
public void setName(String name) {
   
this.name = name;
 
}
 
public String getName() {
   
return name;
 
}
 
 
public void setItems(List<WalletItemData> items) {
   
if (items == null) {
     
this.items = null;
     
return;
   
}
   
   
// TODO I'm not sure request factory will do this or not yet.
   
ArrayList<WalletItemData> a = new ArrayList<WalletItemData>();
   
Iterator<WalletItemData> itr = items.iterator();
   
while(itr.hasNext()) {
     
WalletItemData d = itr.next();
     
if (d.getId() != null && d.getId() > 0) { // null on id to increment
       
// need parentKey, to reference the owned entities
        d
.setId(key, d.getId());
     
}
      a
.add(d);
   
}
   
   
this.items = a;
 
}
 
public List<WalletItemData> getItems() {
   
return items;
 
}

}


Thanks
Brandon Donnelson



Brandon Donnelson

unread,
Oct 19, 2011, 8:34:23 PM10/19/11
to google-we...@googlegroups.com
I figured out how to saved owned entities, but I can't seem to transport them back in the proxy. 

How can I get the children to come along for the ride?

Brandon Donnelson

unread,
Oct 19, 2011, 9:14:38 PM10/19/11
to google-we...@googlegroups.com

Brandon Donnelson

unread,
Oct 31, 2011, 11:26:56 AM10/31/11
to google-we...@googlegroups.com

Patrick Julien

unread,
Oct 31, 2011, 12:00:17 PM10/31/11
to google-we...@googlegroups.com
I didn't see this thread earlier but you might find this information useful. Looking at some of your code, some observations:


1. For WalletData and WalletItemData, you don't have to manually set up the owning key yourself.  See the following:

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

2.

/** 
   * I'm not really using the tokenizer here, but good for example
   */
  @Prefix("Entry")
  public static class Tokenizer implements PlaceTokenizer<SignInPlace> {

    private RequestFactory requestFactory;

    
    public Tokenizer(RequestFactory requestFactory) {
      this.requestFactory = requestFactory;
    }
    

You can't have ctor arguments on a tokenizer, it's created by the framework using GWT.create()

3. Callling r.with()

If you're using an EditorDriver, the driver provides a getPath() method that you give to with().


4. Lastly, even if the AppEngine documentation seems to favor JDO, I've found that JPA is nonetheless easier to use and it's supported on AppEngine too, albeit only 1.0, not >= 2


Brandon Donnelson

unread,
Oct 31, 2011, 8:16:35 PM10/31/11
to google-we...@googlegroups.com
Thanks for looking at my code. I wanted to follow up.

to 1. I was having problems with the implying the parent in the ownership, so I had to do it manually. I have other projects where I use RPC and I don't have to set the parent. For some reason I wasn't able to get it to work in this codebase. I'll try again  Thanks for noticing that.

to 2. I found you can have arguments in the tokenizer. The one you saw was not really being used. Here is a better example: http://code.google.com/p/gwt-examples/source/browse/trunk/WalletInventory/src/com/gonevertical/client/app/activity/places/WalletEditPlace.java

to 3. I'll have to try the editor driver. On the Todo list. 

to 4. I wouldn't/don't mind using JPA, but I could not find a path of success using the annotations to setup the Owned Collections annotations. I tried everything I could think of and settled with this. I do like the concise annotations in JPA although, when it came to Owned Collections in App Engine it failed for me. If you look into the history, I tried twice on this code base. Its most likely operator error. 

Do you know how to annotate owned Collections in JPA. 

Thanks for looking through the code! :)

Brandon Donnelson


Patrick Julien

unread,
Nov 1, 2011, 12:42:08 AM11/1/11
to google-we...@googlegroups.com
1. Well, the previous post has the link to the AppEngine JDO documentation on how to do that but it doesn't work in JPA the same way, more on that later in #4
2. You're right. I've been using gin for so long that I've forgotten about the setFactory method. The reason it works is not because of the class you pointed me too but this one here:

http://code.google.com/p/gwt-examples/source/browse/trunk/WalletInventory/src/com/gonevertical/client/app/ClientFactoryImpl.java

You're constructing your place tokenizers manually. You gain complete control of how you construct you tokenizers but at the expense of having to write the code yourself. In my code, I don't have anything implementing ApplicationPlaceHistoryMapper like you do, it's provided by gin.

However, now that i think about, gin should be able to do the same with ctor arguments provided the necessary Provider<T>s are in place

4. So you did:

@ElementCollection(targetClass=WalletItemData.class)
@CollectionTable(name="items")
@MapKey(name="key")
private List<WalletItemData> items;

What you're asking for is exactly:

@OneToMany(mappedBy="items") // mappedBy is ignored on AppEngine
private List<WalletItemData> items;

and in WalletItemData:
@ManyToOne
private WalletData parent;

but @ManyToOne isn't supported on AppEngine

and what I think you're looking for is something with automatic management of the child's relationship which is:

@OneToMany(mappedBy="items", cascade=ALL) // mappedBy is ignored on AppEngine
private List<WalletItemData> items;

Now, from inside a transaction, any new object you put in items will be persisted, any modified object will be updated and anything removed from the collection will be automatically deleted. You never need to call merge, persist or remove on an EntityManager for any of these operations since this collection is already managed and known to the entity manager.

If you absolutely need to know your parent from the child, outside of it being present in the parent's collection that is, you do it exactly the way you did it by setting and managing the parent key manually. The difference is the object type will be of the key type instead of the actual parent type.

Reply all
Reply to author
Forward
0 new messages