0

JPA CriteriaQuery を使用して複合選択を行う際に問題があります。私は 3 つのテーブル X->Y->Z を持っています。すべての XI には 1 つ以上の Y があり、すべての YI には 1 つ以上の Z があります。X オブジェクトがあり、1 つの X に対して Z のすべての出現を選択しようとしています。

私が使用しているコード:

  CriteriaBuilder cb = em.getCriteriaBuilder();
  CriteriaQuery<Z> criteriaQuery = cb
          .createQuery(Z.class);      
  Root<Z> fromZ = criteriaQuery.from(Z.class);

  X xObj = new X(xObjId);

  Subquery<Y> subquery = criteriaQuery.subquery(Y.class);
  Root<Y> fromY = subquery.from(Y.class);
  subquery.select(fromY.<Y> get("Yid")).distinct(true)
          .where(cb.equal(fromY.get("Xid"), xObj));

  criteriaQuery
          .select(fromZ)
          .where(cb.and(
                  cb.in(from.get("Yid")).value(subquery),
                  cb.and(cb.equal(from.get("Zcolumn1"), 0),
                          cb.equal(from.get("Zcolumn2"), 1))))
          .orderBy(cb.asc(from.get("Zcolumn3")));

  TypedQuery<Z> typedQuery = em.createQuery(criteriaQuery);
  List<Z> results = typedQuery.getResultList();

Xid と Yid は、それぞれの Y Bean と Z Bean の外部キーです。

無効な SQL があるため、このコードは実行ポイントでエラーを生成します。

SELECT t0.Zcolumn1, t0.Zcolumn2, t0.Zcolumn3, FROM Z t0 WHERE (t0.Yid IN ( SELECT t1.Yid.t1.Yid FROM Y t1 WHERE (t1.Xid = ?)) AND (((t0.Zcolumn1 = ?) AND (t0.Zcolumn2 = ?))) ORDER BY t0.Zcolumn3 ASC

サブクエリによって Yid が 2 回生成される理由がわかりません。修正方法もわかりません。見つけて適応させた例によると、これはうまくいくと思います。SubQuery を使用するのはこれが初めてなので、私のコード スタイルの可能性のあるばかげたエラーを許してください :)

ありがとうございました。

4

1 に答える 1

0

subQuery を使用している理由がまったくわかりません。

このはるかに単純なアプローチにより、指定された X インスタンスにリンクされた Z のすべての発生が得られます。フィールドの命名を少し変更しました。次のように、それぞれ X と Y の OneToMany プロパティですysCollectionzsCollection

@Entity
public class X {
    ...
    @OneToMany(mappedBy="xId")
    private List<Y> ysCollection;
    ...
}

目標を誤解している場合は、お知らせください。

X xObj;
CriteriaQuery<Z> cq = cb.createQuery(Z.class);
Root<X> root = cq.from(X.class);
Join<X, Y> ys = root.join("ysCollection");
Join<Y, Z> zs= ys.join("zsCollection");
cq.distinct(true);
cq.where(cb.equal(root.get("id"), xObj.getId()));
cq.select(zs);

または、MetaModel を使用して:

X xObj;
CriteriaQuery<Z> cq = cb.createQuery(Z.class);
Root<X> root = cq.from(X.class);
Join<X, Y> ys = root.join(X_.ysCollection);
Join<Y, Z> zs= ys.join(Y_.zsCollection);
cq.distinct(true);
cq.where(cb.equal(root.get(X_.id), xObj.getId()));
cq.select(zs);
于 2013-03-26T19:29:45.207 に答える