如何向 NamedQuery/MappedSelect 添加预取?

Posted

技术标签:

【中文标题】如何向 NamedQuery/MappedSelect 添加预取?【英文标题】:How Can I Add a Prefetch to a NamedQuery/MappedSelect? 【发布时间】:2018-02-07 22:53:23 【问题描述】:

我的模型中有一个命名查询,它设置为获取数据对象。

<query name="artists" type="SQLTemplate" root="obj-entity" root-name="Artist">
    <property name="cayenne.GenericSelectQuery.fetchingDataRows" value="false"/>
    <sql><![CDATA[SELECT * FROM Artist]]></sql>
</query>

我的实际查询更复杂,无法使用 ObjectSelect 完成。

我想添加一个预取,但我还没有想出我喜欢的解决方案。这是我尝试过的:

    错误

    List<Artist> artists = MappedSelect.query(...).select(context);
    artists.forEach( artist -> artist.getPaintings.size() );
    

    这不会从数据库中刷新,并且需要为每个艺术家单独查询。

    直接拨打RelationshipQuery

    List<Artist> artists = MappedSelect.query(...).select(context);
    for (Artist artist : artists) 
        Query query = new RelationshipQuery(artist.getObjectId(), Artist.PAINTINGS.getName());
        ((ToManyList) artist.getPaintings()).setObjectList(context.performQuery(query));
    
    

    我认为这并没有完成它应该做的所有事情,它仍然需要为每个艺术家单独查询。

    子类MappedSelect 公开getReplacementQuery

    class MySelect<T> extends MappedSelect<T> 
        ...
        public SQLTemplate getReplacementQuery(...) 
            return (SQLTemplate) super.getReplacementQuery(...);
        
    
    MySelect query = new MySelect(...);
    SQLTemplate template = query.getReplacementQuery(context.getEntityResolver());
    template.addPrefetch(Artist.PAINTINGS.disjointById());
    template.setCacheStrategy(QueryCacheStrategy.NO_CACHE);
    List<Artist> artists = query.select(context);
    

    我不喜欢访问私有 API。我还认为,如果我在访问替换查询后设置任何参数,此解决方案可能会失败。

    更改包以访问BaseMetadata

    package org.apache.cayenne.query;
    ...
    MappedSelect<Artist> query = MappedSelect.query(...);
    BaseQueryMetadata metaData = (BaseQueryMetadata) query.getMetaData();
    metaData.mergePrefetch(Artist.PAINTINGS.disjointById());
    metaData.setCacheStrategy(QueryCacheStrategy.NO_CACHE);
    Artist artist = query.select(context);
    

    这似乎稍微好一点,但我仍在访问私有 API,它需要在不同的包中编写代码(或使用反射)。它仍然有一个强制的沮丧。

    重新获取对象

    List<Artist> artists = MappedSelect.query(...).select(context);
    ObjectSelect.query(Artist.class)
        .where(ExpressionFactory.matchAnyExp(artists))
        .prefetch(Artist.PAINTINGS.disjoint())
        .cacheStrategy(QueryCacheStrategy.NO_CACHE);
        .select(context);
    

    这是我试图避免的,因为我正在重新获取刚刚检索到的行。

是否有一种首选方法可以将预取添加到命名查询,例如我可以在模型中设置的属性?或者有什么好办法让关系恢复?

【问题讨论】:

【参考方案1】:

MappedSelectSQLSelect 都不支持预取,这是一个不幸的遗漏(我会跟进以填补 Cayenne 中的这一空白)。您可能必须切换到旧的、不太漂亮但功能齐全的 SQLTemplate 查询:

SQLTemplate q = new SQLTemplate(MyEntity.class, "SELECT * FROM...");
q.addPrefetch(MyEntity.SOME_RELATIONSHIP.getName());

【讨论】:

我期待 API 的变化。同时,将 SQL 保留在模型中对我来说很重要,所以我找到了这个解决方案:SQLTemplate q = ((SQLTemplateDescriptor) context.getEntityResolver().getQueryDescriptor(...)).buildQuery();

以上是关于如何向 NamedQuery/MappedSelect 添加预取?的主要内容,如果未能解决你的问题,请参考以下文章

如何向用户显示警报?

如何向 jtextfield 添加填充

如何向免费用户显示不同的页面,向付费用户显示不同的页面

如何向 CountDownTimer 添加闹钟?

如何加快向 ListView 添加项目?

如何使用 xmpppy 向聊天室发送消息?