Java 如何使用JPA的CriteriaAPI构造多列“WHERE…IN”表达式?

Java 如何使用JPA的CriteriaAPI构造多列“WHERE…IN”表达式?,java,jpa-2.0,eclipselink,criteria-api,Java,Jpa 2.0,Eclipselink,Criteria Api,对于具有多列ID的实体,我们需要将数据库中尚未存在的所有对象持久化到给定列表中。由于要检查的对象数量很大,并且存储中的对象数量可能非常大,因此我们的想法是使用其多列私钥和WHERE。。。在里面使用CriteriaAPI构造的类型语句,以便在持久化之前可以从列表中删除它们 以下是尝试执行此操作的代码: public void persistUnique(List<CdrEntity> cdrs) { // find all the CDRs in the col

对于具有多列ID的实体,我们需要将数据库中尚未存在的所有对象持久化到给定列表中。由于要检查的对象数量很大,并且存储中的对象数量可能非常大,因此我们的想法是使用其多列私钥和WHERE。。。在里面使用CriteriaAPI构造的类型语句,以便在持久化之前可以从列表中删除它们

以下是尝试执行此操作的代码:

    public void persistUnique(List<CdrEntity> cdrs) {
        // find all the CDRs in the collection that are already in the DB
        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        CriteriaQuery<CdrEntity> query = criteriaBuilder.createQuery(CdrEntity.class);
        Root<CdrEntity> cdrRoot = query.from(CdrEntity.class);
        query.select(cdrRoot).where(cdrRoot.in(cdrs));
        List<CdrEntity> nonUnique = entityManager.createQuery(query).getResultList();
        // remove nonUnique elements from crds and persist
        ...
    }
从本质上讲,在主键列的适当列名应该是空的地方,会添加一些参数,然后用null值绑定这些参数。除此之外,查询还可以,如果前四个?被实际列名替换,则执行时会得到所需的结果

然而,似乎呼叫中。。。直接在根上没有期望的结果。如果直接使用实体是不可能的,我希望有某种表达式可以表示多个列,然后可以作为调用.in…的接收器,但我还没有找到任何表达式


因此,问题是:如何正确地做到这一点?还是JPA根本不可能?或者只是EclipseLink中有一个bug?

有趣的尝试,以及生成的奇怪SQL,SQL看起来左侧正确,但右侧不正确。请为此记录一个bug,这是可以支持的。在2.5开发版本中也尝试一下,它可能会起作用

JPA标准API不支持嵌套数组,因此这超出了JPA规范

您可以为左侧的id字段创建一个路径表达式列表,并使用CriteriaBuilder文字表达式来实现此目的,这可能会奏效


JPA实现这一点的标准方法是迭代对象列表,或在表达式中进行每个对象的id比较。

感谢您的快速响应。不幸的是,使用CriteriaBuilder.literal方法似乎没有达到目的;事实上,它生成的SQL更糟糕:WHERE?在?,,,,,,,…-然后继续绑定实际路径和实体对象。Root.in方法几乎做了正确的事情,从直觉上看,这应该是Root.in应该做的,毕竟,根总是代表一个实体,对吗?不幸的是,EclipseLink 2.5不是这个项目的一个选项,因为我们即将发布,只是试图在这里干净地处理一个重复记录的问题,但我会让它转一转,看看它是否有效果。如果没有,我将按照建议提交一个bug。我最终解决了这个问题,在列表上迭代并添加了一长串的OR表达式,其中包含不同PK列的and比较-这正是我希望避免的,真的。它非常难看,并且在一个地方产生了我所见过的最大数量的括号,但它是有效的。既然你建议这是标准方式,我就认为你的答案是可以接受的。
[EL Fine]: sql:...--SELECT SUBINDEX, ... FROM CDRS WHERE ((?, ?, ?, ?) IN ((?, ?, ?, ?), (?, ?, ?, ?), ...))
bind => [null, null, null, null, 2, 1362400759, 19415, 176, ...]