【问题标题】:Preserve arbitrary order in a collection defined with JDO in Google App Engine在 Google App Engine 中使用 JDO 定义的集合中保留任意顺序
【发布时间】:2014-03-07 17:01:14
【问题描述】:

我正在将我的代码移至 Java7 和最新的 Datanucleus App Engine 插件,但我遇到了订单问题。

我有一个祖先类,它拥有一些需要维护用户定义的特定顺序的子类。所以我使用了没有任何@Extension 的@Order 注释。 使用以前的 JDO 版本,一切正常,现在我的单元测试失败了,因为它不再找到这个 _INTEGER_IDX 属性。

我创建了一个简单的测试项目,遵循此文档Owned one-to-many relationship,以便从一个新示例开始,但它仍然无法正常工作: GitHub-project.

我在这里总结一下模型:

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Book {
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    @Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
    private String key = null;

    @Persistent
    private String title = null;

    @Persistent(mappedBy="book")
    @Order
    private List<Chapter> chapters = null;

.. 和..

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Chapter {
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    @Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
    private String key = null;

    @Persistent
    private String name = null;

    @Persistent
    private Book book = null;

.. 这是失败的单元测试:

@Test
public void testJdoDependingEntities() throws EntityNotFoundException {
    PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory("transactions-optional");

    PersistenceManager pm = pmf.getPersistenceManager();

    Book bookJdo = null;

    try {
        pm.currentTransaction().begin();

        bookJdo = new Book("myTitle");
        Chapter cpt1 = new Chapter("myname1");
        Chapter cpt2 = new Chapter("myname2");
        Chapter cpt3 = new Chapter("myname3");
        Chapter cpt4 = new Chapter("myname4");
        Chapter cpt5 = new Chapter("myname5");
        Chapter cpt6 = new Chapter("myname6");

        bookJdo.getChapters().add(cpt1);
        cpt1.setBook(bookJdo);
        bookJdo.getChapters().add(cpt2);
        cpt2.setBook(bookJdo);
        bookJdo.getChapters().add(cpt3);
        cpt3.setBook(bookJdo);
        bookJdo.getChapters().add(cpt4);
        cpt4.setBook(bookJdo);
        bookJdo.getChapters().add(cpt5);
        cpt5.setBook(bookJdo);
        bookJdo.getChapters().add(cpt6);
        cpt6.setBook(bookJdo);

        pm.makePersistent(bookJdo);

        pm.currentTransaction().commit();
    } catch(Exception e) {
        e.printStackTrace();
    }
    finally {
        if(pm.currentTransaction().isActive()) {
            pm.currentTransaction().rollback();
        }
        pm.close();
    }

    Entity book = datastore.get(KeyFactory.stringToKey(bookJdo.getKey()));
    assertEquals("myTitle", book.getProperty("title"));

    Query query = new com.google.appengine.api.datastore.Query(
            "Chapter",
            KeyFactory.stringToKey(bookJdo.getKey()));
    FetchOptions options = FetchOptions.Builder.withDefaults();

    QueryResultList<Entity> resultEntity = datastore.prepare(query)
            .asQueryResultList(options);

    assertEquals(6, resultEntity.size());

    // print values
    System.out.println("From ancestor query:");
    System.out.println("All the props: "+resultEntity.get(0).getProperties());
    System.out.println("idx prop: "+resultEntity.get(0).getProperty("chapters_INTEGER_IDX"));
    System.out.println();

    Entity chapter = datastore.get(resultEntity.get(0).getKey());
    System.out.println("All the props: "+chapter.getProperties());
    System.out.println("idx prop: "+chapter.getProperty("chapters_INTEGER_IDX"));

    // test against JUnit
    assertNotNull(resultEntity.get(0).getProperty("chapters_INTEGER_IDX"));
    assertNotNull(chapter.getProperty("chapters_INTEGER_IDX"));
 }

这里是GitHub-project

【问题讨论】:

    标签: java google-app-engine testing jdo datanucleus


    【解决方案1】:

    为什么“Chapter.book”上有一个 mappedBy?那是非法的。如果一个关系是双向的,那么它在没有 FK 的一侧有一个 mappedBy。

    【讨论】:

    • 非常感谢您的建议 Neil,但我尝试删除它仍然存在问题。 (我也将更新示例和 github 存储库)
    • Google 在code.google.com/p/datanucleus-appengine/source/browse/… 下有大量测试,其中包括索引列表;全部通过。查看 HasOneToManyListJDO 和 BidirectionalChildListJDO。除非您查看 LOG 并调试您的配置有什么问题
    • 确实 LOG 记录了与数据存储的所有通信,关于存储的内容,DB 查看器显示存储的内容(列等),因此应该足够简单以便调试
    【解决方案2】:

    找到问题了!

    您应该在 jdoconfig.xml 中添加这一行:

    &lt;property name="datanucleus.appengine.storageVersion" value="PARENTS_DO_NOT_REFER_TO_CHILDREN"/&gt;

    这里是piece of code,其中解释了不同的数据存储配置

    【讨论】:

    • 显然 Google 自己的测试用例使用“古代存储版本”运行,它们可以处理索引列表。但是很好,你有一个“解决方案”。
    • Mmhhh...不明白你的意思DataNucleus!问题是在我的机器上运行我自己的测试用例(而不是在 Google Cloud 中)。因此,默认情况下 JDO 似乎不再存在 INTEGER_IDX 。现在我正在按照code.google.com/p/datanucleus-appengine/wiki/… 迁移云中的数据
    • 另一张发帖者向您指出了在您的机器上运行的测试。他们足够清楚地展示了索引列表。默认情况下,它们使用最新的存储版本(但也使用旧的存储版本运行)。它们将集合中元素的 ID 存储在所有者的属性中。不需要这种人为的 INTEGER_IDX 属性,并且在代码中依赖这种实现细节是不好的做法。使用这个新的存储版本时,顺序会被保留,就像使用旧的存储版本一样。在这个新的存储版本中,集合详细信息的存储效率更高
    • mmhhh.. 我会更好地审查样本。我继续使用 INTEGER_IDX 的主要需要是可以在不触及整个集合的情况下快速重新排序子集合,但只处理那些 INTEGER_IDX 属性
    猜你喜欢
    • 1970-01-01
    • 2010-12-02
    • 1970-01-01
    • 2012-06-14
    • 1970-01-01
    • 1970-01-01
    • 2012-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多