Подзапрос JPA дважды генерирует идентификатор в SQL-запросе

У меня проблема с составным выбором с использованием JPA CriteriaQuery. У меня есть три таблицы X->Y->Z , для каждого X у меня есть один или несколько Y и для каждого Y у меня есть один или несколько Z. У меня есть объект X, и я пытаюсь выбрать все вхождения Z для одного X .

Код, который я использую:

  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 и Z.

Этот код генерирует ошибку в точке выполнения, потому что у меня есть недопустимый 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 = ?)) И ((t0.Zcolumn1 = ?) И (t0.Zcolumn2 = ?))) ЗАКАЗАТЬ ПО t0.Zcolumn3 ASC

Я не понимаю, почему Yid генерируется дважды по подзапросу, и понятия не имею, как это исправить, согласно примерам, которые я нашел и адаптировал, я думаю, что это должно работать. Я впервые работаю с SubQuery, так что простите за мой стиль кода возможные глупые ошибки :)

Спасибо.


person Nicolae Birlea    schedule 26.03.2013    source источник
comment
разве Subquery<Y> subquery = criteriaQuery.subquery(Y.class); не должно быть Subquery<Yid> subquery = criteriaQuery.subquery(Yid.class);?   -  person cosmincalistru    schedule 26.03.2013
comment
Yid , это не класс , нотация, которую я использовал, может немного сбивать с толку, Y это класс, а Yid - это внешний ключ в Z и X и первичный ключ в Y.   -  person Nicolae Birlea    schedule 27.03.2013
comment
(внешний ключ только для Z...)   -  person Nicolae Birlea    schedule 27.03.2013


Ответы (1)


Я не уверен, почему вы вообще используете subQuery.

Этот гораздо более простой подход даст вам все вхождения Z, связанные с данным экземпляром X. Я немного изменил наименование полей: ysCollection и zsCollection — это свойства OneToMany в X и Y соответственно, как показано ниже:

@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);

Или, используя метамодель:

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);
person perissf    schedule 26.03.2013
comment
хорошо, вы должны объяснить мне, что такое ysCollection и zsCollection. - person Nicolae Birlea; 27.03.2013