網頁

2014年2月2日 星期日

GAE Java - Parent / Child pair

Last Update: 2014/02/02 16:39+08
Type:Note

--- Intro ---

我們在 GAE Toturial 可以看到 Relastionship 的設置
Owned One/One, One/Many
Unowned One/One, One/Many, Many/Many

這篇要講在設計上, 用 One/Many
但使用上, 卻常常要從 child 去找 parent
例如, 一個網站上的一個使用者, 他可能擁有多個 email
該怎麼 declare entities



--- Content ---

考慮下述 entities
@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class MyUser implements java.io.Serializable {
 @PrimaryKey
 @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
 private Key key;
 @Persistent
 private Date createDate;
 @Persistent
 private String name;

 @Persistent(mappedBy = "relUser")
 private Set relSetUserEMail = new HashSet();//one/many
}

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class MyUserEMail implements java.io.Serializable {
 @PrimaryKey
 @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
 private Key key;//(*1)
 @Persistent//(*1)
 private String email;
 @Persistent
 private Date createDate;
 @Persistent
 private String emailType;
 @Persistent
 private MyUser relUser;//one/one
}
在設計 entity 時, 宣告 變數的那個, 視為 parent
我們宣告 MyUser(parent)/MyUserEMail(child) : one/many
然後為了讓 child 可以方便找到 parent 又宣告了 MyUserEMail(parent)/MyUser(child) : one/many
再宣告 mappedBy = "relUser" 告知其相對應的欄位

我想討論一下一個狀況, 如果我們執行下述代碼
pm.currentTransaction().begin();
user = new MyUser(nowTime);
user.setName(userService.getCurrentUser().getNickname());
pm.makePersistent(user);

userEMail = new MyUserEMail(nowTime);
userEMail.setEmail(email);
user.getRelSetUserEMail().add(userEMail);
pm.makePersistent(user);
這是可以完成工作的
我們丟了一個 child 給 parent 認養
並且設定了 MyUserEMial.relUser 為相對應的欄位

但有件事要注意一下,
使用 PersistenceManager 是不允許變更 Parent, 所以一旦被丟到資料庫裡就不能變動了
而且一定要先 make(makePersistent) Parent

所以, 如果你把 (*1) 那2行註解掉
也就是用 "非自動產生" 的 DataType 作為 identity
那麼代碼怎麼改都沒法進資料庫
1. 用上述代碼 - 先 setEmail, add(userEMail) 再 makePersistent(user)
  會出現 "MyUserEMail(xxxxx) has already been persisted without a parent" 的錯誤訊息
  應該是因為email為key, 設置時就會被送到資料庫做驗證
2. 先 add(userEMail), makePersistent(user) 再 setEmail
  會產生 "Cannot have a null primary key field"


所以, 大概只能用 Unowned Relationship
另外是, 若 要用 Owned Relationship, 則 entity 的 PK 必須為 Key



沒有留言:

張貼留言