【问题标题】:How to avoid joins using subqueries inside Specification?如何避免在规范中使用子查询进行连接?
【发布时间】:2020-06-15 19:13:42
【问题描述】:

我需要根据只有在 5 次关联后才能找到的数据来获取一些实体。我想避免在途中加入所有表并使用 IN 子句。

这是我发现的仅使用几个实体的简单实现:

@Entity
public class Foo {
    @Id
    private Long idFoo;
    private String name; 
}

@Entity
public class Bar {
    @Id
    private Long idBar;
    @ManyToOne
    @JoinColumn(name = "idFoo")
    private Foo foo; 
}

假设我需要根据 Bar 属性列出所有 Foo 对象,比如说 idBar:

class FilterFooByIdBar extends Specification<Foo> {
    public Predicate toPredicate(Root<Foo> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        var subquery = query.subquery(Foo.class);
        var barRoot = subquery.from(Bar.class);

        subquery.select(barRoot.get("foo"))
                .where(builder.equal(barRoot.get("idBar"), 1L));

        return root.in(subquery);
    }
}

这可行,但生成的 SQL 是这样的:

select foo0_.idFoo, foo0_.name 
from Foo foo0_ 
where foo0_.idFoo in (
    select bar1_.idFoo 
    from Bar bar1_ cross join Foo foo2_ 
    where bar1_.idFoo=foo2_.idFoo 
    and bar1_.idBar=1
);

我认为子查询内的连接是无用的,违背了我的目标,我想做这样的事情:

select foo0_.idFoo, foo0_.name 
from Foo foo0_ 
where foo0_.idFoo in (
    select bar1_.idFoo 
    from bar bar1_  
    where bar1_.idBar=1
);

有没有办法改变规范并实现它?

【问题讨论】:

    标签: java hibernate spring-data


    【解决方案1】:

    使用 exists 子查询来代替,这通常更快,并且如果您使用的是最新的休眠版本,还可以消除连接。

    class FilterFooByIdBar extends Specification<Foo> {
        public Predicate toPredicate(Root<Foo> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            var subquery = query.subquery(Foo.class);
            var barRoot = subquery.from(Bar.class);
    
            subquery.select(cb.literal(1))
                    .where(cb.and(
                       cb.equal(barRoot.get("idBar"), 1L),
                       cb.equal(barRoot.get("foo"), root)
                    );
    
            return cb.exists(subquery);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-11-10
      • 2014-05-18
      • 1970-01-01
      • 2016-06-28
      • 2021-05-05
      • 1970-01-01
      • 2021-10-02
      • 1970-01-01
      • 2020-03-24
      相关资源
      最近更新 更多