У меня проблема с HQL-запросом
Три класса
ClassOne - это мой бизнес-объект
public class ClassOne {
private int id;
private int status;
private Set<ClassTwo> classTwos;
+ other fields/getters/setters/constructor etc
}
ClassTwo упоминается в наборе ClassOne и является своего рода историей объекта ClassOne
public class ClassTwo {
private int id;
private int oldStatus;
private int newStatus;
private String message;
//+ getters/setters/constructor etc
}
ClassThree - это мой DTO / VO только с одним classTwo (не всей историей)
public class ClassThree {
private int id;
private int status;
private ClassTwo classTwo;
public ClassThree(int pId, int pStatus, ClassTwo pClassTwo) {
id=pId;
status=pStatus;
classTwo=pClassTwo;
}
//+ getters/setters etc
}
Теперь я хотел бы создать запрос HQL, подобный этому:
Я хотел бы получить все объекты ClassThree с определенным статусом и, если он существует, новейшим ClassTwo с определенным newStatus.
Например:
Я хотел бы получить все DTO (ClassThree) ClassOne, чей статус теперь равен 1, но ранее в их истории это было 2, и я хотел бы иметь последний объект ClassTwo с 2 как newStatus.
SELECT new ClassThree(c1.id, c1.status, c2)
FROM ClassOne c1
LEFT JOIN c1.classtwos c2 (...)
и (...) я не знаю, что делать, я даже не уверен, что это соединение / выборка
Осмотрелся и уже довольно много пробовал, но понятия не имел. Особенно с получением соединения я получаю некоторые ошибки Hibernate, такие как org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list
.
Получение BusinessObject таким образом не проблема
SELECT distinct(c1)
FROM ClassOne c1
LEFT OUTER JOIN FETCH c1.classtwos c2
и я получаю ClassTwos в качестве моего поля.
Заранее спасибо,
Jacob
P.S .: Может быть важно одно: ClassTwo не имеет ссылки на ClassOne !!
P.P.S: Простой запрос SQL, который решает мою проблему, выглядит примерно так:
select * from classone as c1 left join (select * from classtwo where newstatus = 2) c2 on c1.id=c2.id_classone whete c1.status = 1
Этот запрос работает и получает всю информацию, необходимую для моей БД PostGreSQL, но мне бы очень хотелось, чтобы HQL продолжал работать, особенно по причинам обслуживания и т. Д. ...
Обновление с обходным решением:
Получение идентификаторов всех ClassOnes со статусом 1
Collection<Integer> ids = null;
ids = (Collection<Integer>) getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session pSession) throws HibernateException, SQLException {
return getDocumentIds(pSession, pStatus);
}
}
);
Теперь я получаю все DTO, которые были в статусе 2 (спасибо Ивану) с:
Именованный запрос Document.dto.with.transfer
SELECT new DocumentDTO(d.id, d.status, histo)
FROM Document d
LEFT JOIN d.histories histo
WHERE
d.id in (:ids)
AND
(histo.id =
SELECT MAX(innerhisto.id)
FROM Document innerd
JOIN innerd.histories innerhisto
WHERE d.id = innerd.id AND innerhisto.newStatus = 21)
(в моем коде я использую несколько именованных запросов)
List<DocumentDTO> lRes = new ArrayList<DocumentDTO>();
Query lQuery = getSession(false).getNamedQuery("Document.dto.with.transfer");
lQuery.setParameterList("ids", ids);
lResultList.addAll(lQuery.list());
После этого я удаляю все идентификаторы, найденные в моем списке. Идентификаторы
for (DocumentDTO dto : lResultList) {
ids.remove(dto .getId());
}
Я делаю третий запрос, используя второй конструктор для DTO, инициализируя мою историю с помощью фиктивного объекта.
Именованный запрос Document.dto.simple
SELECT new DocumentDTO(d.id, d.status)
FROM Document d
WHERE
d.id in (:ids)
(еще один именованный запрос)
lQuery = getSession(false).getNamedQuery("Document.dto.simple");
lQuery.setParameterList("ids", ids);
lResultList.addAll(lQuery.list());
и готово.