将 SQL 'IN' 子查询转换为 JPA 条件查询时出现问题
Problem with translating SQL 'IN' subquery into a JPA Criteria Query
我正在尝试将此 SQL 查询转换为 JPA 条件查询:
select distinct student0_.name
from vnic03.student student0_
where (exists(select teacher0_.social_number
from vnic03.teacher teacher0_
where teacher0.social_number = ?
and teacher0_.school_id in (select school0_.id
from vnic03.school school0_
where school0_.student_id = student0_.id)))
这些是表格(我已经简化并重命名它们以便将它们张贴在这里,实际上它们有几百万个条目):
现在我有以下代码:
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<String> searchQuery = criteriaBuilder.createQuery(String.class);
Root<Student> root = searchQuery.from(Student.class);
List<Predicate> restrictions = new ArrayList<>();
Subquery<Teacher> subQuery = searchQuery.subquery(Teacher.class);
Root<Teacher> fromSchoolSubQuery = subQuery.from(Teacher.class);
List<Predicate> subRestrictions = new ArrayList<>();
Subquery<School> subQuery2 = searchQuery.subquery(School.class);
Root<School> fromSchoolSubSubQuery = subQuery2.from(School.class);
List<Predicate> subSubRestrictions = new ArrayList<>();
subRestrictions.add(criteriaBuilder.equal(fromSchoolSubQuery.get(Social_number), userInput));
subRestrictions.add(criteriaBuilder.equal(fromSchoolSubQuery.get(School_ID), subQuery2.select(fromSchoolSubSubQuery.get(School_ID)).where(criteriaBuilder.equal(fromSchoolSubSubQuery.get(Student_ID), root.get(student_ID)))));
restrictions.add(criteriaBuilder.exists(subQuery.select(
fromSchoolSubQuery.get(Social_number)).where(
subRestrictions.toArray(new Predicate[0]))));
searchQuery.distinct(true)
.select(root.get(name))
.where( restrictions.toArray(new Predicate[restrictions.size()]) );
TypedQuery<String> query = em.createQuery(searchQuery)
List<String> nameList = query.getResultList();
但这转化为:
select distinct student0_.name
from vnic03.student student0_
where (exists(select teacher0_.social_number
from vnic03.teacher teacher0_
where teacher0.social_number = ?
and teacher0_.school_id = (select school0_.id
from vnic03.school school0_
where school0_.student_id = student0_.id)))
所以我只需要在最后的 and
部分中将 =
替换为 in
即可。我在其他 SO 问题中发现是这样的:
CriteriaBuilder.In<String> in = criteriaBuilder.in( ??? );
或
Path<Object> path = root.get(student_ID);
CriteriaBuilder.In<Object> in = criteriaBuilder.in(path);
但我就是不知道如何正确使用它...
所以如果你知道如何只翻译这部分,它可能已经为我解决了:
where teacher0_.school_id **in** (select school0_.id
from vnic03.school school0_
where school0_.student_id = student0_.id)))
阅读本文第 5 章后我找到了解决方案:https://www.baeldung.com/jpa-criteria-api-in-expressions
Subquery<School> subQueryForInExpression = searchQuery.subquery(School.class);
Root<School> fromSchoolSubQuery = subQueryForInExpression.from(School.class);
subQueryForInExpression.select(fromSchoolSubQuery.get(student_id)).where(criteriaBuilder.equal(fromSchoolSubQuery.get(school_id), root.get(student_id)));
subQueryForInExpression
表示IN
表达式中的Select
子查询:
select school0_.id
from vnic03.school school0_
where school0_.student_id = student0_.id
现在我们必须将 in
表达式添加到子限制中,这是通过 CriterisBuilder.in(...).value(subQueryForInExpression)
:
完成的
subRestrictions.add(criteriaBuilder.in(fromSchoolSubQuery.get(school_id)).value(subQueryForInExpression));
我正在尝试将此 SQL 查询转换为 JPA 条件查询:
select distinct student0_.name
from vnic03.student student0_
where (exists(select teacher0_.social_number
from vnic03.teacher teacher0_
where teacher0.social_number = ?
and teacher0_.school_id in (select school0_.id
from vnic03.school school0_
where school0_.student_id = student0_.id)))
这些是表格(我已经简化并重命名它们以便将它们张贴在这里,实际上它们有几百万个条目):
现在我有以下代码:
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<String> searchQuery = criteriaBuilder.createQuery(String.class);
Root<Student> root = searchQuery.from(Student.class);
List<Predicate> restrictions = new ArrayList<>();
Subquery<Teacher> subQuery = searchQuery.subquery(Teacher.class);
Root<Teacher> fromSchoolSubQuery = subQuery.from(Teacher.class);
List<Predicate> subRestrictions = new ArrayList<>();
Subquery<School> subQuery2 = searchQuery.subquery(School.class);
Root<School> fromSchoolSubSubQuery = subQuery2.from(School.class);
List<Predicate> subSubRestrictions = new ArrayList<>();
subRestrictions.add(criteriaBuilder.equal(fromSchoolSubQuery.get(Social_number), userInput));
subRestrictions.add(criteriaBuilder.equal(fromSchoolSubQuery.get(School_ID), subQuery2.select(fromSchoolSubSubQuery.get(School_ID)).where(criteriaBuilder.equal(fromSchoolSubSubQuery.get(Student_ID), root.get(student_ID)))));
restrictions.add(criteriaBuilder.exists(subQuery.select(
fromSchoolSubQuery.get(Social_number)).where(
subRestrictions.toArray(new Predicate[0]))));
searchQuery.distinct(true)
.select(root.get(name))
.where( restrictions.toArray(new Predicate[restrictions.size()]) );
TypedQuery<String> query = em.createQuery(searchQuery)
List<String> nameList = query.getResultList();
但这转化为:
select distinct student0_.name
from vnic03.student student0_
where (exists(select teacher0_.social_number
from vnic03.teacher teacher0_
where teacher0.social_number = ?
and teacher0_.school_id = (select school0_.id
from vnic03.school school0_
where school0_.student_id = student0_.id)))
所以我只需要在最后的 and
部分中将 =
替换为 in
即可。我在其他 SO 问题中发现是这样的:
CriteriaBuilder.In<String> in = criteriaBuilder.in( ??? );
或
Path<Object> path = root.get(student_ID);
CriteriaBuilder.In<Object> in = criteriaBuilder.in(path);
但我就是不知道如何正确使用它...
所以如果你知道如何只翻译这部分,它可能已经为我解决了:
where teacher0_.school_id **in** (select school0_.id
from vnic03.school school0_
where school0_.student_id = student0_.id)))
阅读本文第 5 章后我找到了解决方案:https://www.baeldung.com/jpa-criteria-api-in-expressions
Subquery<School> subQueryForInExpression = searchQuery.subquery(School.class);
Root<School> fromSchoolSubQuery = subQueryForInExpression.from(School.class);
subQueryForInExpression.select(fromSchoolSubQuery.get(student_id)).where(criteriaBuilder.equal(fromSchoolSubQuery.get(school_id), root.get(student_id)));
subQueryForInExpression
表示IN
表达式中的Select
子查询:
select school0_.id
from vnic03.school school0_
where school0_.student_id = student0_.id
现在我们必须将 in
表达式添加到子限制中,这是通过 CriterisBuilder.in(...).value(subQueryForInExpression)
:
subRestrictions.add(criteriaBuilder.in(fromSchoolSubQuery.get(school_id)).value(subQueryForInExpression));