【问题标题】:JPA criteria API translates the 'in' expression to multiple 'OR'JPA 标准 API 将“in”表达式转换为多个“OR”
【发布时间】:2018-01-25 19:32:31
【问题描述】:

带有“in”表达式的 JPA 条件 API 转换为多个“OR”而不是“in”

例如

我的主要模特

public class Person {
    ...

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "department_id")
    private Department department;

    ...
}

多对一关系

public class Department {
    @Id
    @Column(name="department_id")
    private Integer departmentId;

    @OneToMany(mappedBy="department")
    private List<Person> person;

    ...
}

在persistence.xml中定义了这两个模型(注意:它没有指定任何db方言)

<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
    version="2.1">

    <persistence-unit name="primary" transaction-type="JTA">

        <jta-data-source>java:openejb/Resource/jdbc/myDS</jta-data-source>

        <class>com.xyz.Person</class>
        <class>com.xyz.Department</class>
        ...

        <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>

        <properties>
            <property name="openjpa.Log" value="${open.jpa.log}" />
            <property name="openjpa.ConnectionFactoryProperties" value="printParameters=true" />
            <property name="openjpa.RuntimeUnenhancedClasses" value="unsupported" />
        </properties>
    </persistence-unit>

</persistence>

以下是使用 Criteria API 构建查询的代码:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Person> criteriaQuery = cb.createQuery(Person.class);
Root<Person> personRoot = criteriaQuery.from(Person.class);

criteriaQuery.select(personRoot);

List<Predicate> predicateList = new ArrayList<>();
predicateList.add(personRoot.get(Person_.department).get(Department_.departmentId).in(Arrays.asList(1, 2, 3)));
// Using list because I actually need to add multiple conditions

criteriaQuery.where(predicateList.toArray(new Predicate[0]));

TypedQuery<Person> searchQuery = em.createQuery(criteriaQuery);

searchQuery.getResultList();

这会以以下格式打印查询:

SELECT t0.person_id, ... 
FROM person t0 
WHERE ((t0.department_id = ? OR t0.department_id = ? OR t0.department_id = ?) AND t0.department_id IS NOT NULL)

但我应该得到的是

SELECT t0.person_id, ... 
FROM person t0 
WHERE t0.department_id IN (?, ?, ?)

环境:

  • Tomee 7.0.3
  • 嵌入式 OpenJPA
  • Mariadb

更新:

我也尝试过如下添加mariadb方言,但没有帮助

<property name="openjpa.jdbc.DBDictionary" value="mariadb" />

【问题讨论】:

  • 可能后端(方言)没有'in' ???。使用什么真实数据库?
  • 它是 mariadb。 Mariadb 支持'in'
  • 尝试将java.sql.Array 传递给in - 使用SQL "... in(?)"
  • 尝试将“(1,2,3)”指定为 PARAMETER,并在运行时提供 List 作为参数值。
  • 在 SQL 中,一个表达式:x IN (1, 2, 3) 等同于 x=1 or x=2 or x=3,它给出的结果完全相同。你为什么担心它?我个人不会关心它。

标签: java jpa openjpa


【解决方案1】:

解决方案是使用表达式,例如:

List<Long> departmentIdsList = new ArrayList();
departmentIdsList.add(1L);
departmentIdsList.add(2L);
departmentIdsList.add(3L);
Expression<Long> exp = personRoot.get("departmentId");//"departmentId" field name to be equated
predicateList.add(exp.in(departmentIdsList));

上面的 sn-p 应该像子句一样评估

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-12
    • 2011-05-27
    • 1970-01-01
    • 2012-05-30
    • 2011-10-18
    • 2021-10-16
    • 2021-01-11
    • 1970-01-01
    相关资源
    最近更新 更多