7

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

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

    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
        ...
    }

但是,至少使用 EclipseLink 2.4.1,这是实际发送到数据库的内容(为了便于阅读,省略了一些输出):

[EL Fine]: sql:...--SELECT SUBINDEX, ... FROM CDRS WHERE ((?, ?, ?, ?) IN ((?, ?, ?, ?), (?, ?, ?, ?), ...))
bind => [null, null, null, null, 2, 1362400759, 19415, 176, ...]

本质上,在主键列的适当列名应该在的地方,添加了许多参数,然后绑定(值为 null)。除此之外,查询很好,如果前四个 ?s 被实际的列名替换,则执行所需的结果。

然而,直接调用.in(...)aRoot似乎没有预期的结果。如果无法直接使用实体,我希望有某种Expression可以代表多个列的列,然后这些列可能是调用的接收者.in(...),但我找不到任何列。

所以,问题是:如何正确地做到这一点?或者 JPA 根本不可能?或者只是 EclipseLink 中存在一个错误?

4

1 回答 1

2

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

JPA Criteria API 不支持嵌套数组,所以这超出了 JPA 规范。

您可以为左侧的 id 字段创建路径表达式列表,并为此使用 CriteriaBuilder literal() 表达式,它可能会起作用。

执行此操作的 JPA 标准方法是在每个对象的 id 比较的表达式中迭代对象列表和 or()。

于 2013-03-04T16:26:29.443 回答