来自無處不在 原文地址:http://blog.chaoskey.com/2010/04/29/201004291034
我个人认为,这是GAE/J的JDO实现中最有问题的一部分,我查看了 GAE/Java 的官方论坛,很多人对此提出了疑问,但是没有很好的解决方案。 相关的GAE/J文档所谓的范例根本不全,没有一个完全可运行的例子,甚至连最简单的例子都没有。 还好,功夫不负有心人,我终于找到了一个解决方案,现在分享出来。
按照GAE/J 的文档,它所谓的关系包括: Owned Relationships 和 Unowned Relationships 两类。 本文说是前者,至于后者根本不是一般意思的“关系”,因为他的关系完全要由程序逻辑来保证。
这里还是继续以GAE/J 文档中的例子的完善来作为这里例子:(相关说明见红色粗体的标注)
1) Employee 1->* ContactInfo ( One-to-Many)
@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable="true") public class Employee { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) @Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true") private String encodedKey; //编码后的Key,自动生成,只读 @Persistent @Extension(vendorName="datanucleus", key="gae.pk-id", value="true") private Long id; //自动生成,只读,使用 encodedKey/id的组合,即保证了能够使用GAE/J 关系,又能够顺从一般的习惯 @Persistent private String firstName; @Persistent private String lastName; @Persistent private Date hireDate = new Date(); @Persistent(mappedBy = "employee") List<ContactInfo> contactInfoSets; //一对多关系的标注 //这里忽略了相关的 set/get 方法 }
2) ContactInfo 1->1 Employee ( One-to-One)
@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable="true") public class ContactInfo { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) @Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true") private String encodedKey; //编码后的Key,自动生成,只读 @Persistent @Extension(vendorName="datanucleus", key="gae.pk-id", value="true") private Long id; //自动生成,只读,使用 encodedKey/id的组合,即保证了能够使用GAE/J 关系,又能够顺从一般的习惯 @Persistent private String streetAddress; @Persistent private String city; @Persistent private String stateOrProvince; @Persistent private String zipCode; @Persistent @Extension(vendorName="datanucleus", key="gae.parent-pk", value="true") private Key employeeKey; //父实体组的设置 @Persistent private Employee employee; //一对一关系的标注 //这里忽略了相关的 set/get 方法 }
3) 使用范例:
PersistenceManager pm = PMF.get().getPersistenceManager(); try { Employee employee = new Employee(); employee.setFirstName("张"); employee.setLastName("三"); pm.makePersistent(employee); Key employeeKey = KeyFactory.stringToKey(employee.getEncodedKey()); resp.getWriter().println("employeeKey=" + employeeKey); ContactInfo contactInfo1 = new ContactInfo(); contactInfo1.setStreetAddress("青山湖区"); contactInfo1.setCity("南昌市"); contactInfo1.setStateOrProvince("江西省"); contactInfo1.setZipCode("366123"); contactInfo1.setEmployee(employee); contactInfo1.setEmployeeKey(employeeKey); //将employee设为父实体 employee.getContactInfoSets().add(contactInfo1); //保证employee的一对多 pm.makePersistent(contactInfo1); resp.getWriter().println("contactInfo1Key=" + KeyFactory.stringToKey(contactInfo1.getEncodedKey())); ContactInfo contactInfo2 = new ContactInfo(); contactInfo2.setStreetAddress("刘家铺"); contactInfo2.setCity("海淀区"); contactInfo2.setStateOrProvince("北京市"); contactInfo2.setZipCode("100000"); contactInfo2.setEmployee(employee); contactInfo2.setEmployeeKey(employeeKey); //将employee设为父实体 employee.getContactInfoSets().add(contactInfo2); //保证employee的一对多 pm.makePersistent(contactInfo2); resp.getWriter().println("contactInfo2Key=" + KeyFactory.stringToKey(contactInfo2.getEncodedKey())); }catch(Exception e){ e.printStackTrace(); } finally { pm.close(); }
4)运行结果
employeeKey=Employee(92)contactInfo1Key=Employee(92)/ContactInfo(93)contactInfo2Key=Employee(92)/ContactInfo(94)
最后的运行结果表明: Employee(92) ,ContactInfo(93) ,ContactInfo(94) 属于同一个实体组系,并且 Employee(92) 是 ContactInfo(93) 和 ContactInfo(94)的公共父实体。 应该存储在同一个节点上(Google的存储节点)。