无法在GAE JDO中持久化对象

5

我完全不了解JDO和GAE,一直在努力使我的数据层持久化任何代码!

我面临的问题可能非常简单,但是无论我尝试什么解决方案,似乎都找不到解决方法。

首先,问题是:(稍微简化了一下,但仍包含所有必要的信息) 我的数据模型如下:

User:
    (primary key)
    String emailID
    String firstName

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

这是最初的数据模型。我实现了一个CarPK对象,以获取用户和注册的复合主键。然而,这遇到了各种问题(我将在另一个时间/问题中解决)。
然后我进行了如下设计更改: 用户:(未更改)
Car:
(primary key)
String fauxPK (here fauxPK = user.getEmailID() + SEP + registration)
User user
String registration
String model

对于用户而言,这很好用,可以插入和检索用户对象。然而,如果我尝试插入一辆汽车对象,会收到以下错误:

"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

我去了提供的链接,那里解释了如何创建密钥,但他们一直在谈论“实体组”和“实体组父项”。但我似乎找不到任何解释“实体组”或“实体组父项”的文章或网站。
我可以尝试再研究一下,看是否能以某种方式存储对象,但我的耐心正在逐渐消磨殆尽,而且我更愿意理解并实现,而不是相反。
因此,我会感激任何文档(即使它很大),涵盖所有这些要点,并最好有一些超越非常基本的数据建模的示例。
谢谢您阅读这么长的帖子 :)
2个回答

13

我担心你不会喜欢这个答案。GAE JDO必须以非常特定的方式使用,并且存在许多限制,你必须遵守才能有效地使用它。仔细阅读文档。对于你现在看到的问题,你可能需要多次阅读此部分:

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

GAE JDO有拥有和非拥有关系。请参考上面的文档,了解所拥有和未拥有的示例。我相信你希望CarUser之间有一个非拥有关系。请注意,在Google App Engine文档中关于非拥有关系的说明:

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

除了拥有关系之外,JDO API 还提供了管理非拥有关系的工具。App Engine 的 JDO 实现尚未实现此功能,但不用担心,您仍然可以使用 Key 值来管理这些关系,而不是使用模型对象的实例(或实例集合)。这意味着,在使用 GAE JDO 时,您不应该为 Car 和 User 类之间的非拥有关系使用直接引用。相反,您应该在它们之间使用间接引用,即 Car 应该有一个指向 User 键的字段,而不是对 User 本身的直接引用。您遇到的一些问题是因为 GAE JDO 无法处理您在代码中建模此关系的方式。
询问者继续说道:
去了那里建议的链接,那里解释了如何创建 Keys,但他们一直在谈论“实体组”和“实体组父项”。但我似乎找不到任何解释“实体组”或“实体组父项”的文章或网站。

实体组 - 一个一开始就被持久化在一起的对象图。例如,因为Car直接引用了一个User,所以当你第一次持久化给定的Car实例时,也会持久化它所引用的User实例,这个Car实例和这个User实例将成为同一个实体组的一部分。如果这个User实例已经被持久化,不管是独立地还是作为另一个Car实例的一部分,那么这个User实例已经在另一个实体组中了。"拥有"关系应该位于同一个实体组中。请注意,GAE JDO事务只能修改1个实体组 - 多余的将引发异常。

实体组父级 - 一个顶层/根("父级")持久化的类。在上面的例子中,当你第一次持久化给定的Car实例时,也会持久化它所引用的User实例,这个Car实例是实体组的父级。像User这样的"拥有"的"子"类嵌入了它的父类(Car)的键到自己(User)的键中。如果你从数据库中提取一个Car实例,然后尝试访问这个Car所引用的User,那么GAE JDO将使用Car的键来查找相应的User(因为目标User的键已经将父级Car的键嵌入到自己的键中了)。

提问者收到了这个错误信息:

"不能使用java.lang.String作为主键并作为子对象" 请注意文档中的这个语句: “子类必须有一个关键字段,其类型可以包含父关键信息:Key或编码为字符串的Key值。请参见创建数据:关键字以获取有关关键字段类型的信息。” 这意味着,“子”类必须使用特定类型的键(即能够在子键中封装其父键的键)。对于实体组父类,即非子类,LongString是合适的。但是,“子”类必须为其键使用Key编码为字符串的Key类型。错误消息指示Car类将User类视为“拥有的”“子”类,因此User类必须使用适用于子类的键类型,但User类未使用适用于子类的键类型(非编码字符串)。"
解决眼前的问题的方法是将Car和User模型建立为一个未拥有关系,通过将Car从直接引用User更改为间接引用,存储相关User的键。整体修复可能包括仔细研究如何将对象模型适配到GAE JDO的框架中(一旦您浏览文档并尝试理解它)。这可能包括手动管理类之间的某些关系。
如果这可以安慰您,我自己也正在处理与GAE JDO相同类型的问题(我甚至也有一个Car类!)。

首先感谢您花时间提供如此详细的答案!非常感谢...我最初尝试建立拥有关系,但由于键存在各种问题而无法实现。由于时间不多,而且这个项目并不太涉及数据库模型,所以我决定采用间接引用。下一个项目会回到实验中。 - Basil Dsouza
@Basil - 我认为你想要一个“未拥有”的关系,但是你编写了一个“拥有”的关系(通过使用直接引用)。正如这个答案所指出的那样,转换为间接引用是有效的修复方法 - 没有必要进一步“实验”。 - Bert F
实际上,从一开始我就想要一个拥有关系。我甚至已经创建了代表用户和汽车注册的PK对象作为键。然而,这并没有起作用,甚至出现了更令人困惑的问题。目前的修复方案是可接受的,但我仍然对学习正确的做法感兴趣。因为当前的修复方案将大表格视为关系型数据库。 - Basil Dsouza
@Basil - 我明白了。我认为用户和汽车可以独立存在,因此它们之间存在“未拥有”的关系。但是,如果在您的应用程序/域中一个不存在而另一个存在,则我理解了。很遗憾,在GAE JDO中建模关系有很多限制,这使得表达它们变得困难和不直观。我相信随着您的使用,它会变得更容易。 - Bert F


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接