7

複数列 ID を持つエンティティの場合、DB にまだ存在していない特定のリスト内のすべてのオブジェクトを永続化する必要があります。チェックするオブジェクトの数が多く、ストレージ内のオブジェクトの数が非常に多くなる可能性があるため、複数列の秘密鍵と "WHERE ... IN (. ..)" 条件 API を使用して構築された type ステートメントであり、永続化する前にリストから削除できます。

これを試みるコードは次のとおりです。

    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を使用すると、これは実際にDBに送信されるものです(読みやすくするために一部の出力は省略されています):

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

基本的に、主キー列の適切な列名があるべき場所に、いくつかのパラメーターが追加され、後で (値が null で) バインドされます。それとは別に、クエリは問題なく、最初の 4 つの ?s が実際の列名に置き換えられれば、目的の結果で実行されます。

.in(...)ただし、 a を直接呼び出すとRoot、望ましい結果が得られないようです。エンティティを直接使用できない場合は、複数の列を表すことができる何らかの種類があり、Expressionそれが への呼び出しの受信者になる可能性があると予想され.in(...)ますが、見つけることができませんでした。

問題は、これを適切に行うにはどうすればよいかということです。または、JPAではまったく不可能ですか?それとも、EclipseLink に単にバグがあるのでしょうか?

4

1 に答える 1

2

興味深い試みであり、生成された奇妙なSQLであるため、SQLは左側が正しいように見えますが、右側は正しくありません。これについてはバグをログに記録してください。サポートされる可能性があります。(2.5 devビルドでも試してみてください。動作する可能性があります)。

JPA Criteria APIはネストされた配列をサポートしていないため、これはJPA仕様を超えています。

左側のidフィールドのパス式のリストを作成し、これにCriteriaBuilderリテラル()式を使用すると、機能する可能性があります。

これを行うJPAの標準的な方法は、オブジェクトのリストと各オブジェクトのID比較の式内のor()を反復処理することです。

于 2013-03-04T16:26:29.443 に答える