如何向 NamedQuery/MappedSelect 添加预取?
How Can I Add a Prefetch to a NamedQuery/MappedSelect?
我的模型中有一个命名查询,设置为获取数据对象。
<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);
这是我要避免的,因为我正在重新获取刚刚检索到的行。
是否有一种首选方法可以将预取添加到命名查询中,例如我可以在模型中设置的 属性?或者有什么好的方法可以挽回感情?
MappedSelect
和 SQLSelect
都不支持预取,这是一个不幸的遗漏(我会跟进以填补 Cayenne 中的这个空白)。您可能需要切换到较旧的、不那么漂亮但功能齐全的 SQLTemplate
查询:
SQLTemplate q = new SQLTemplate(MyEntity.class, "SELECT * FROM...");
q.addPrefetch(MyEntity.SOME_RELATIONSHIP.getName());
我的模型中有一个命名查询,设置为获取数据对象。
<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);
这是我要避免的,因为我正在重新获取刚刚检索到的行。
是否有一种首选方法可以将预取添加到命名查询中,例如我可以在模型中设置的 属性?或者有什么好的方法可以挽回感情?
MappedSelect
和 SQLSelect
都不支持预取,这是一个不幸的遗漏(我会跟进以填补 Cayenne 中的这个空白)。您可能需要切换到较旧的、不那么漂亮但功能齐全的 SQLTemplate
查询:
SQLTemplate q = new SQLTemplate(MyEntity.class, "SELECT * FROM...");
q.addPrefetch(MyEntity.SOME_RELATIONSHIP.getName());