在Criteria API

时间:2017-06-16 10:20:00

标签: jpa criteria-api

有两个具有多对多关系的实体类,我正在尝试创建一个查询,该查询测试一个表中所有实体是否存在任何关系。我被困了,因为似乎没有办法通过Criteria API引用JoinTable。

示例实体:

@Entity
@Table(name="man")
public class Man  {

    @Id
    @GeneratedValue
    private Long id;

}


@Entity
@Table(name="woman")
public class Woman  {

    @Id
    @GeneratedValue
    private Long id;

    @ManyToMany
    @JoinTable(
            name="man_woman",
            joinColumns=
            @JoinColumn(name="woman_id", referencedColumnName="id"),
            inverseJoinColumns=
            @JoinColumn(name="man_id", referencedColumnName="id")
    )
    private Set<Man> men;
}

我想使用条件API创建一个查询,这会产生SQL,例如:

select m.id, 
       case when exists(select * from man_woman mw where mw.man_id=m.id) then 1 else 0
from man; 

到目前为止,我提出的最好成绩如下:

CriteriaQuery<Tuple> criteriaQuery = criteriaBuilder.createTupleQuery();

Root<Man> from = criteriaQuery.from(Man.class);

Subquery<Long> subquery = criteriaQuery.subquery(Long.class);

Root<Woman> sub_from = subquery.from(Woman.class);  
SetJoin<Woman, Man> setJoin = sub_from.join(Woman_.men);
subquery.select(sub_from.get(Woman_.id));
subquery.where(from.in(setJoin.get(Man_.id)));

criteriaQuery.multiselect(from.alias("man_entity"),
        criteriaBuilder.selectCase()
                .when(
                        criteriaBuilder.exists(subquery)
                        , true)
                .otherwise(false)
                .alias("knows_any_women")
);

return em.createQuery(criteriaQuery).getResultList()

导致SQL包含额外的连接:

select m.id, 
       case when exists(select w.id 
                        from woman w 
                            inner join man_woman mw on w.id = mw.woman_id
                            inner join man m2 on m2.id = mw.man_id
                        where m.id in (m2.id)
                        ) 
            then 1 else 0
from man; 

我想这句话最终会被优化为看起来像我想要的那样 - 但有没有办法让它从一开始变得更简单?

0 个答案:

没有答案