对于具有多列ID的实体,我们需要在给定列表中保留DB中尚未存在的所有这些对象。由于要检查的对象数量很大,并且存储中的对象数量可能非常大,因此我们的想法是使用多列私钥和“WHERE ... IN(。”来从List中选择现有对象。 ..)“使用条件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)。除此之外,查询很好,如果前四个?被实际的列名替换,则执行所需的结果。
然而,似乎直接在.in(...)
上调用Root
没有获得所需的结果。如果直接使用实体是不可能的,我希望有某种Expression
可以代表多个列,然后可以成为调用.in(...)
的接收者,但我还没有能够找到任何。
所以,问题是:如何正确地做到这一点?或者JPA根本不可能吗?或者EclipseLink中只有一个错误?
答案 0 :(得分:2)
有趣的尝试,以及生成的奇怪的SQL,SQL看起来左侧是正确的,但不是正确的。请记录一个错误,这是可以支持的。 (也可以在2.5 dev构建中尝试它,它可能会工作)。
JPA Criteria API不支持嵌套数组,所以这超出了JPA规范。
您可以为左侧的id字段创建路径表达式列表,并为此使用CriteriaBuilder literal()表达式,它可能有用。
JPA标准的方法是在每个对象的id比较的表达式中迭代对象列表和or()。