问题 JPA条件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();
}
明显, 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)
- 移动 姓 领域到 学科
- 使用本机查询
- 使用实体图
是不可接受的。
我对可以直接声明和使用的东西感兴趣 哪里 条款(只生产 CriteriaBuilder 和/或单身 根,就像 treat()
条款),如果确实存在。
13000
2017-12-13 14:02
起源
答案:
解决方案是,使用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();
}
请注意 双重演员,它避免了编译错误,并允许在同一个表上执行查询子句。这会产生:
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%'))
无需更改模型或其他任何内容。
6
2017-12-21 08:25
更新:
你期待的sql - 虽然它可以用纯jpa crtieria api生成 - 它不会起作用并且会抛出一个异常,因为你(hibernate)不能实例化抽象类主题。
引起:org.hibernate.InstantiationException:无法实例化
抽象类或接口:
如果这个类不是抽象的,那就有效。喜欢这个:
CriteriaBuilder b = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Contact> q;
q = b.createQuery(Contact.class);
Root r = q.from(Contact.class);
q.select(r);
q.distinct(true);
q.where(
b.or(
b.like(r.get(Contact_.name),"t%"),
b.and(
b.equal(r.get(Contact_.contact_type),"customer"),
b.like(r.get(Customer_.lastName),"t%")
)
)
);
return getEntityManager().createQuery(q).getResultList();
(我的客户是您的人,我的主题类是联系人类)
以只读方式访问鉴别器列可能是一种有效的解决方法。
如果discriminator_column是contact_type,请执行以下操作:
@Column(name = "contact_type",insertable = false,updatable = false)
@XmlTransient
private String contact_type;
接触是一个抽象类,客户作为子类,如下:
CriteriaBuilder b = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Contact> q = b.createQuery(Contact.class);
Root<Contact> r = q.from(Contact.class);
q.distinct(true);
q.where(
b.or(
b.like(r.get(Contact_.name), "t%"),
b.and(
b.equal(r.get(Customer_.contact_type), "customer"),
b.like(r.get(Customer_.name), "%t")
)
)
);
return getEntityManager().createQuery(q).getResultList();
产生
select
distinct contact0_.id as id2_1_,
contact0_.contact_type as contact_1_1_,
contact0_.name as name3_1_
from
Contact contact0_
where
contact0_.name like ?
or contact0_.contact_type=?
and (
contact0_.name like ?
)
4
2017-12-16 22:50
答案:
解决方案是,使用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();
}
请注意 双重演员,它避免了编译错误,并允许在同一个表上执行查询子句。这会产生:
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%'))
无需更改模型或其他任何内容。
6
2017-12-21 08:25
更新:
你期待的sql - 虽然它可以用纯jpa crtieria api生成 - 它不会起作用并且会抛出一个异常,因为你(hibernate)不能实例化抽象类主题。
引起:org.hibernate.InstantiationException:无法实例化
抽象类或接口:
如果这个类不是抽象的,那就有效。喜欢这个:
CriteriaBuilder b = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Contact> q;
q = b.createQuery(Contact.class);
Root r = q.from(Contact.class);
q.select(r);
q.distinct(true);
q.where(
b.or(
b.like(r.get(Contact_.name),"t%"),
b.and(
b.equal(r.get(Contact_.contact_type),"customer"),
b.like(r.get(Customer_.lastName),"t%")
)
)
);
return getEntityManager().createQuery(q).getResultList();
(我的客户是您的人,我的主题类是联系人类)
以只读方式访问鉴别器列可能是一种有效的解决方法。
如果discriminator_column是contact_type,请执行以下操作:
@Column(name = "contact_type",insertable = false,updatable = false)
@XmlTransient
private String contact_type;
接触是一个抽象类,客户作为子类,如下:
CriteriaBuilder b = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Contact> q = b.createQuery(Contact.class);
Root<Contact> r = q.from(Contact.class);
q.distinct(true);
q.where(
b.or(
b.like(r.get(Contact_.name), "t%"),
b.and(
b.equal(r.get(Customer_.contact_type), "customer"),
b.like(r.get(Customer_.name), "%t")
)
)
);
return getEntityManager().createQuery(q).getResultList();
产生
select
distinct contact0_.id as id2_1_,
contact0_.contact_type as contact_1_1_,
contact0_.name as name3_1_
from
Contact contact0_
where
contact0_.name like ?
or contact0_.contact_type=?
and (
contact0_.name like ?
)
4
2017-12-16 22:50