java - 将 SQL 'IN' 子查询转换为 JPA Criteria 查询时出现问题

标签 java sql jpa criteria-api

我正在尝试将此 SQL 查询转换为 JPA Criteria 查询:

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)))  

这些是表格(我已经简化并重命名了它们以便将它们发布在这里,实际上它们有几百万个条目):

my tables

现在我有以下代码:

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 即可。我在其他问题中发现了类似这样的内容:

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 表达式添加到 subRestrictions,这是通过 CriterisBuilder.in(...).value(subQueryForInExpression) 完成的:

subRestrictions.add(criteriaBuilder.in(fromSchoolSubQuery.get(school_id)).value(subQueryForInExpression));

关于java - 将 SQL 'IN' 子查询转换为 JPA Criteria 查询时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60758439/

相关文章:

mysql - 如何使用MySQL将2个不同结构的表合并为1个表?

java - 如何在play框架中使用多个实体管理器-使用spring data JPA?

java - Hibernate - 按列分组、收集到列表和限制

java - Java 中的方法签名是否包括其返回类型?

java - 阻塞队列与信号量

java - pretty-print 。忽略空格

java - 添加两个数字而不是合并

sql - 如何在 Tarantool 中从 SQL 调用 C 函数?

python - 将列从 csv 动态导入到 sqlite3 和 python 中的数据库表中

java - 为什么不从实体层次结构来创建 dto?