我想执行一个匹配特定子类属性的查询,所以我正在尝试使用treat()
.
在这个例子中我想要:
名称以"a"开头的
所有科目,或所有科目,即姓名以"a"开头的人
private Listq1() { CriteriaBuilder b = em.getCriteriaBuilder(); CriteriaQuery q = b.createQuery(Subject.class); Root 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(); }
显然,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%')
虽然我期待:
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%')
有没有办法使用条件构建器生成预期的查询?
注意
使用另一个根 -q.from(Person.class)
使用子查询 - q.subquery(Person.class)
将lastName字段移动到Subject
使用本机查询
使用实体图
是不可接受的.
我对可以在WHERE子句中直接声明和使用的东西感兴趣(仅从CriteriaBuilder和/或单个Root生成,就像treat()
子句一样),如果它确实存在的话.
解决方案是,使用Hibernate并在此特定场景中,非常简单:
private Listq1() { CriteriaBuilder b = em.getCriteriaBuilder(); CriteriaQuery q = b.createQuery(Subject.class); Root 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 ) (Root>) r).get(Person_.lastName), "a%")))); return em.createQuery(q).getResultList(); }
注意双重转换,它避免了编译错误,并允许在同一个表上执行查询子句.这会产生:
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%'))
无需更改模型或其他任何内容.