QueryDSL生成交叉连接

时间:2014-08-17 22:04:57

标签: hibernate jpa spring-data-jpa querydsl

我希望为结果提供内容过滤。我的(为简洁而编辑)实体如下所示:

节点:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Node {
    @Id
    @GeneratedValue
    public Integer id;
}

场景:

@Entity
public class Scene extends Node {
    @OneToMany(mappedBy = "scene", /*fetch = FetchType.EAGER, */cascade = CascadeType.ALL)
    public List<Source> sources;
}

来源:

@Entity
public class Source extends Node {
    @ManyToOne
    public Scene scene;

    @Enumerated(EnumType.ORDINAL)
    public SourceType type;
}

以下是我希望实现的过滤器示例。

给定SourceTypes的集合,我希望选择所有场景,使得这个场景由这些类型中的每一个的源引用。我使用带有以下谓词的QueryDSL实现了这一点:

private Predicate filterBySourceType(Collection<SourceType> it) {
    BooleanBuilder bb = new BooleanBuilder();

    for (SourceType st : it)
        bb.and(QScene.scene.sources.any().type.eq(st));

    return bb.getValue();
}

将一系列这些谓词组合在一起以提供整体查询。甚至只选择一个SourceType时,生成的查询如下所示:

Hibernate: select count(scene0_.id) as col_0_0_ from Scene scene0_ inner join Node scene0_1_ on scene0_.id=scene0_1_.id where exists (select 1 from Source source1_ inner join Node source1_1_ on source1_.id=source1_1_.id where (source1_.id in (select sources2_.id from Source sources2_ inner join Node sources2_1_ on sources2_.id=sources2_1_.id where scene0_.id=sources2_.scene_id)) and source1_.type=?)

我相信上面发生的是交叉连接,因此(2k场景,1k源)查询需要几秒钟。

我尝试切换到具体的类多态,以消除Node连接,但没有明显的性能提升。

我如何优化该谓词?

1 个答案:

答案 0 :(得分:3)

事实证明,您可以使用JPASubQuery获取CollectionExpression并写出查询,类似于使用普通旧SQL编写它的方式。

        bb.and(QScene.scene.in(
                new JPASubQuery()
                        .from(source)
                        .where(source.type.eq(st))
                        .list(source.scene)
        ));