2

私は JPA 永続性基準 API の第一人者ではありません。それを使用すると、ひどい頭痛がすることがあります。

昨日、私は新しい非常に奇妙な動作に気付きました。私が投稿するコードは、既存の機能するコードの適応であるため、些細なエラーに焦点を合わせないでください。私はグラスフィッシュ 3.1.1 と対応する Eclipse 永続化プラグインと Mysql DB を使用しています。

さまざまなテーブルからデータをフィルター処理する criteriaQuery を作成しました。この基準クエリが 2 回実行されると、間違った SQL クエリが生成されます。理由がわかりません。

public CriteriaQuery createQuery4Count(EntityManager em) {
    Calendar lastDate4Search = GregorianCalendar.getInstance();
    javax.persistence.criteria.CriteriaBuilder cb = em.getCriteriaBuilder();
    javax.persistence.criteria.CriteriaQuery cq = cb.createQuery();
    javax.persistence.criteria.Root<Permessimercepath> checkPointRt = cq.from(Permessimercepath.class);
    javax.persistence.criteria.Path<Permessimerce> permessimerceClass = checkPointRt.get(Permessimercepath_.permessimerce);
    Predicate checkPointDatePredicate = cb.isNull(checkPointRt.get(Permessimercepath_.dataTransito));
    Predicate checkPointAreaPredicate = cb.equal(checkPointRt.get(Permessimercepath_.iDArea), area);
    Predicate datePredicate = cb.greaterThanOrEqualTo(permessimerceClass.get(Permessimerce_.datafine), lastDate4Search.getTime());
    Predicate isValidPredicate = cb.lt(permessimerceClass.get(Permessimerce_.statopermesso), Permessimerce.COMPLETED);
    cq.where(cb.and(checkPointAreaPredicate, checkPointDatePredicate, datePredicate, isValidPredicate));
    cq.select(cb.countDistinct(checkPointRt));
    return cq;
}

 CriteriaQuery myCriteriaQuery = createQuery4Count(getEntityManager())
 javax.persistence.Query q = getEntityManager().createQuery(myCriteriaQuery );
 Long Result = ((Long) q.getSingleResult()).intValue();

 // second query created with the same criteriaQuery 
 q = getEntityManager().createQuery(myCriteriaQuery );
 Long Result2 = ((Long) q.getSingleResult()).intValue();

生成されたSQLは

// First and correct one
SELECT COUNT(t0.ID_permesso) FROM permessimercepath t0 WHERE EXISTS (SELECT t1.ID_permesso FROM permessimerce t2, permessimercepath t1 WHERE ((((t0.ID_permesso = t1.ID_permesso) AND (t0.CheckPointIndex = t1.CheckPointIndex)) AND ((((t1.ID_Area = ?) AND (t1.DataTransito IS NULL)) AND (t2.Data_fine >= ?)) AND (t2.Stato_permesso < ?))) AND (t2.ID_permesso = t1.ID_permesso))) 
bind => [3 parameters bound]


// Second and wrong one
 SELECT COUNT(t0.ID_permesso) FROM permessimercepath t0, permessimerce t2, permessimercepath t1 WHERE (((((t1.ID_Area = ?) AND (t1.DataTransito IS NULL)) AND (t2.Data_fine >= ?)) AND (t2.Stato_permesso < ?)) AND (t2.ID_permesso = t1.ID_permesso))

なぜそれが起こるのか誰もわからない場合は、もっと簡単な方法で再現することができます.

ありがとうフィリッポ

4

2 に答える 2

0

実装でバグを見つけたようです。Hibernate では、わずかに似ている (つまり、より複雑ではあるが異なる) ケースが正常に機能します。また、 JPA 仕様のセクション「6.8 Query Modification」では、次の再利用が推奨されています。CriteriaQuery

CriteriaQuery オブジェクトは、TypedQuery オブジェクトが作成されてから実行される前または後に変更できます。たとえば、そのような変更には、where 述語または選択リストの置換が必要になる場合があります。したがって、変更により、同じ CriteriaQuery の「ベース」が複数のクエリ インスタンスに再利用される可能性があります。

于 2012-05-18T17:43:50.567 に答える
0

問題は方法に関連しているようEntityManager.createQuery(CriteriaQuery)です。ドキュメントを確認しましたが、このメソッドが CriteriaQuery を変更するかどうかについては何も言及されていません。通常、このメソッドは渡されたパラメーターを変更しないと予想されます。EntityManager.createQuery(CriteriaQuery)ただし、取得しているのは、メソッドが渡されたパラメーターを変更することを示唆しています。

この場合、毎回コードgetEntityManager()を呼び出す前に createQuery4Count( )を呼び出す必要があります。EntityManager.createQuery(CriteriaQuery)

于 2012-05-18T10:44:15.073 に答える