JPA 条件 API 查询子类 属性
JPA criteria API query subclass property
我想执行匹配特定子类 属性 的查询,所以我尝试使用 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%')
有没有办法使用条件生成器生成预期的查询?
注意
- 使用另一个 Root -
q.from(Person.class)
- 使用子查询 -
q.subquery(Person.class)
- 将 lastName 字段移动到 Subject
- 使用本机查询
- 使用实体图
不可接受.
我对可以直接在 WHERE 子句中声明和使用的东西感兴趣(仅从 CriteriaBuilder and/or 单个 Root,就像 treat()
子句一样),如果它确实存在的话。
更新:
你的期望 sql - 虽然它可以用纯 jpa crtieria 生成 api - 它不会工作并且会抛出异常,因为你(休眠)无法实例化抽象 class 主题。
Caused by: org.hibernate.InstantiationException: Cannot instantiate
abstract class or interface:
如果 class 不是抽象的,它就可以工作。像这样:
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();
(我的客户是你的人,我的主题class是联系人class)
以只读方式访问鉴别器列可能是适合您的解决方法。
如果 discriminator_column 是 contact_type 做:
@Column(name = "contact_type",insertable = false,updatable = false)
@XmlTransient
private String contact_type;
然后联系人是抽象的class,客户作为子class如下:
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 ?
)
在这种特定情况下,使用 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();
}
注意双重转换,它避免了编译错误,并允许在相同的table 上执行查询子句。这会生成:
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%'))
无需更改模型或其他任何内容。
我想执行匹配特定子类 属性 的查询,所以我尝试使用 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%')
有没有办法使用条件生成器生成预期的查询?
注意
- 使用另一个 Root -
q.from(Person.class)
- 使用子查询 -
q.subquery(Person.class)
- 将 lastName 字段移动到 Subject
- 使用本机查询
- 使用实体图
不可接受.
我对可以直接在 WHERE 子句中声明和使用的东西感兴趣(仅从 CriteriaBuilder and/or 单个 Root,就像 treat()
子句一样),如果它确实存在的话。
更新:
你的期望 sql - 虽然它可以用纯 jpa crtieria 生成 api - 它不会工作并且会抛出异常,因为你(休眠)无法实例化抽象 class 主题。
Caused by: org.hibernate.InstantiationException: Cannot instantiate abstract class or interface:
如果 class 不是抽象的,它就可以工作。像这样:
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();
(我的客户是你的人,我的主题class是联系人class)
以只读方式访问鉴别器列可能是适合您的解决方法。 如果 discriminator_column 是 contact_type 做:
@Column(name = "contact_type",insertable = false,updatable = false)
@XmlTransient
private String contact_type;
然后联系人是抽象的class,客户作为子class如下:
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 ?
)
在这种特定情况下,使用 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();
}
注意双重转换,它避免了编译错误,并允许在相同的table 上执行查询子句。这会生成:
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%'))
无需更改模型或其他任何内容。