JPA条件API查询子类属性

Mic*_*tti 11 inheritance hibernate jpa criteria criteria-api

我想执行一个匹配特定子类属性的查询,所以我正在尝试使用treat().

在这个例子中我想要:

名称以"a"开头的
所有科目,或所有科目,即姓名以"a"开头的人

private List<Subject> q1()
{
    CriteriaBuilder b = em.getCriteriaBuilder();

    CriteriaQuery<Subject> q = b.createQuery(Subject.class);
    Root<Subject> r = q.from(Subject.class);
    q.select(r);
    q.distinct(true);
    q.where(
        b.or(
            b.like(r.get(Subject_.name), "a%"),
            b.like(b.treat(r, Person.class).get(Person_.lastName), "a%")));

    return em.createQuery(q).getResultList();
}
Run Code Online (Sandbox Code Playgroud)

显然,Person扩展Subject,Subject是抽象的,继承是SINGLE_TABLE,Subject@DiscriminatorOptions(force = true)其他原因 (非进水).

但生成的SQL是这样的:

select distinct subject0_.ID as ID2_71_, subject0_.CODE as CODE3_71_, ...
from SUBJECT subject0_ 
where subject0_.DTYPE='Person' and (subject0_.name like 'a%' or subject0_.lastName like 'a%')
Run Code Online (Sandbox Code Playgroud)

虽然我期待:

select distinct subject0_.ID as ID2_71_, subject0_.CODE as CODE3_71_, ...
from SUBJECT subject0_ 
where subject0_.name like 'a%' or (subject0_.DTYPE='Person' and subject0_.lastName like 'a%')
Run Code Online (Sandbox Code Playgroud)

有没有办法使用条件构建器生成预期的查询?

注意

  • 使用另一个 -q.from(Person.class)
  • 使用子查询 - q.subquery(Person.class)
  • lastName字段移动到Subject
  • 使用本机查询
  • 使用实体图

是不可接受的.

我对可以在WHERE子句中直接声明和使用的东西感兴趣(仅从CriteriaBuilder和/或单个Root生成,就像treat()子句一样),如果它确实存在的话.

Mic*_*tti 7

解决方案是,使用Hibernate并在此特定场景中,非常简单:

private List<Subject> q1()
{
    CriteriaBuilder b = em.getCriteriaBuilder();

    CriteriaQuery<Subject> q = b.createQuery(Subject.class);
    Root<Subject> r = q.from(Subject.class);
    q.select(r);
    q.distinct(true);
    q.where(
        b.or(
            b.like(r.get(Subject_.name), "a%"),
            b.and(
                b.equal(r.type(), Person.class),
                b.like(((Root<Person>) (Root<?>) r).get(Person_.lastName), "a%"))));

    return em.createQuery(q).getResultList();
}
Run Code Online (Sandbox Code Playgroud)

注意双重转换,它避免了编译错误,并允许在同一个表上执行查询子句.这会产生:

select distinct subject0_.ID as ID2_71_, subject0_.CODE as CODE3_71_, ...
from SUBJECT subject0_ 
where subject0_.DTYPE in ('Office', 'Team', 'Role', 'Person', ...) 
    and (subject0_.name like 'a%' 
        or subject0_.DTYPE='Person' and (subject0_.lastName like 'a%'))
Run Code Online (Sandbox Code Playgroud)

无需更改模型或其他任何内容.