gpt4 book ai didi

java - 将单个 Join 实例传递给多个Specification 实例?

转载 作者:行者123 更新时间:2023-12-02 08:49:51 25 4
gpt4 key购买 nike

相关:Hint HINT_PASS_DISTINCT_THROUGH reduces the amount of Entities returned per page for a PageRequest down to below the configured page size (PostgreSQL)

我正在设置一个基于 JPA 规范的存储库实现,该实现利用 jpa 规范(基于 RSQL 过滤器字符串构建)来过滤结果、定义结果排序并通过“不同”删除任何重复项,否则这些重复项将因加入而返回表。 JPA 规范构建器方法连接多个表并设置“不同”标志:

public final class MySpec implements Specification<Tag>
{
@Override
public Predicate toPredicate(
final Root<Tag> root,
final CriteriaQuery<?> query,
final CriteriaBuilder builder)
{

final Join<Tag, Label> labelsJoin = root.join("labels", JoinType.INNER);
final Join<Label, LabelIdentity> labelIdentityJoin = labelsJoin.join("labelIdentity", JoinType.INNER);
final Predicate labelKeyPredicate = builder.equal(labelIdentityJoin.get("key"), property);

query.distinct(true);

return builder.and(
labelKeyPredicate,
builder.like(labelsJoin.get("value"), argument.replace('*', '%')));
}
}

为了允许按连接表列进行排序,我已将“HINT_PASS_DISTINCT_THROUGH”提示应​​用于相关存储库方法(否则,按连接表列排序会返回类似“排序列必须包含在 SELECT DISTINCT 中”的错误)查询”)。

经过这些更改,过滤和排序似乎可以按要求工作。但是,该提示似乎会导致在构建结果页面后应用“不同”过滤,从而将页面中返回的实体数量从配置的“大小”PageRequest 参数减少到过滤重复项后留下的任何内容出来。

我的问题是:

是否可以通过在不同的Specification实例之间重用Join实例来消除使用不同的需要(从而解决分页问题)?例如,构造 Join 实例,并将相同的 Join 实例传递到每个新的规范实例中(例如通过构造函数)?

例如,我尝试创建类似以下内容的内容,然后将此 JoinCache 实例传递到每个 Specification 实例中,但是,我收到了有关别名不正确的错误,所以不确定是否支持这样的东西?

public class JoinCache
{
private final CriteriaBuilder criteriaBuilder;

private final CriteriaQuery<Tag> criteriaQuery;

private final Root<Tag> tagRoot;

private final Join<Tag, Label> labelJoin;

private final Join<Label, LabelIdentity> labelIdentityJoin;

public JoinCache(final CriteriaBuilder criteriaBuilder)
{
this.criteriaBuilder = criteriaBuilder;
this.criteriaQuery = this.criteriaBuilder.createQuery(Tag.class);
this.tagRoot = criteriaQuery.from(Tag.class);
this.labelJoin = tagRoot.join("labels", JoinType.INNER);
this.labelIdentityJoin = labelJoin.join("labelIdentity", JoinType.INNER);
}

public Join<Tag, Label> getLabelJoin()
{
return labelJoin;
}

public Join<Label, LabelIdentity> getLabelIdentityJoin()
{
return labelIdentityJoin;
}

public CriteriaBuilder getCriteriaBuilder()
{
return criteriaBuilder;
}

public CriteriaQuery<Tag> getCriteriaQuery()
{
return criteriaQuery;
}

public Root<Tag> getTagRoot()
{
return tagRoot;
}
}

更新

使用子查询而不是联接的替代方法(从而完全避免使用不同的需要),但是,我相信 JPA 规范不支持子查询中的排序/排序:

https://hibernate.atlassian.net/browse/HHH-256

public class MySpec implements Specification<Tag>
{
@Override
public Predicate toPredicate(
final Root<Tag> root,
final CriteriaQuery<?> query,
final CriteriaBuilder builder)
{
final String argument = arguments.get(0);

final Subquery<Label> subQuery = query.subquery(Label.class);

final Root<Label> subRoot = subQuery.from(Label.class);

final Predicate tagPredicate = builder.equal(subRoot.get("tag"), root);

final Predicate labelKeyPredicate = builder.equal(subRoot.get("labelIdentity").get("key"), "owner");

subQuery.select(subRoot).where(tagPredicate, labelKeyPredicate, builder.like(subRoot.get("value"), argument.replace('*', '%'));

return builder.exists(subQuery);
}
}

最佳答案

创建对外部查询有副作用的可重用谓词是一种不好的做法(我的意思是query.distinct(true))。您可以使用子查询exists谓词获得相同的结果。

假设Tag实体有@Id Long id字段

public final class MySpec implements Specification<Tag> {

@Override
public Predicate toPredicate(
final Root<Tag> root,
final CriteriaQuery<?> query,
final CriteriaBuilder builder) {

Subquery<Long> subquery = query.subquery(Long.class); // if entity id has Long type
Root<Tag> subRoot = subquery.from(Tag.class);

final Join<Tag, Label> label = subRoot.join("labels", JoinType.INNER);
final Join<Label, LabelIdentity> labelIdentity = label.join("labelIdentity", JoinType.INNER);

final Predicate externalQueryJoinPredicate =
builder.equal(subRoot.get("id"), root.get("id"));
final Predicate labelKeyPredicate =
builder.equal(labelIdentity.get("key"), property);
final Predicate labelValuePredicate =
builder.like(label.get("value"), argument.replace('*', '%'));

subquery.select(subRoot.get("id")).where(
externalQueryJoinPredicate, labelKeyPredicate, labelValuePredicate);

return builder.exists(subquery);
}
}

关于java - 将单个 Join 实例传递给多个Specification 实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60853124/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com