有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

“选择新对象…加入…何处”的java问题

我对HQL查询有问题

三节课

一级是我的商业目标

public class ClassOne {  
  private int id;  
  private int status;
  private Set<ClassTwo> classTwos;  
  + other fields/getters/setters/constructor etc  
}

Class2在ClassOne的集合中被引用,是ClassOne对象的历史记录

public class ClassTwo {  
  private int id;  
  private int oldStatus;  
  private int newStatus;  
  private String message;  
  //+ getters/setters/constructor etc  
}

三级是我的DTO/VO,只有一个二级(不是全部历史)

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查询,如下所示:
我想获得具有特定状态的Class3的所有对象,如果它存在,则获取具有特定newStatus的最新Class2
例如:
我想得到ClassOne的所有DTO(Class3),它们的状态现在是1,但在它们的历史早期是2,我想得到最新的Class2对象,它的状态是2作为newStatus

SELECT new ClassThree(c1.id, c1.status, c2)  
FROM ClassOne c1  
LEFT JOIN c1.classtwos c2 (...)

和(…)我不知道该怎么做,我甚至不确定这是否是一个join/join fetch

环顾四周,已经尝试了很多次,但没有任何线索。尤其是使用join-fetch时,我会遇到一些休眠错误,比如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  

我的专业是二班

提前感谢,
雅各布

附言:有一件事可能很重要,二班和一班没有关系

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可以继续使用,尤其是出于维护等原因

使用变通解决方案更新:

获取状态为1的所有类的ID

Collection<Integer> ids = null;
ids = (Collection<Integer>) getHibernateTemplate().execute(
  new HibernateCallback() {
    public Object doInHibernate(Session pSession) throws HibernateException, SQLException {
      return getDocumentIds(pSession, pStatus);
    }
  }
);

现在我得到了所有处于状态2的DTO(多亏了Ivan):

命名查询文档。dto。具有转移

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

之后,我从我的ID列表中删除所有已经找到的ID

for (DocumentDTO dto : lResultList) {
  ids.remove(dto .getId());
}

我使用DTO的第二个构造函数执行第三个查询,用一个虚拟对象初始化我的历史记录

命名查询文档。dto。简单的

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

一切都结束了


共 (1) 个答案

  1. # 1 楼答案

    要包含没有历史记录的文档,我们应该使用LEFT JOIN并测试空集合,然后使用子查询(SELECT COUNT(...))来检测从未处于状态2的所有文档。最后一个OR-clause用于获取具有指定状态的最后一个历史记录

    以下是HQL查询:

    SELECT new DocumentDto(doc.id, doc.status, hist) 
    FROM Document doc 
    LEFT JOIN doc.histories hist 
    WHERE doc.status = :docStatus 
    AND (size(doc.histories) = 0 
    OR (SELECT COUNT(innerhist) 
        FROM Document innerdoc JOIN innerdoc.histories innerhist 
        WHERE innerdoc.id=doc.id AND innerhist.newStatus = :historyStatus) = 0
    OR (hist.newStatus = :historyStatus AND hist.id = 
        (SELECT max(innerhist.id) 
         FROM Document innerdoc 
         JOIN innerdoc.histories innerhist 
         WHERE innerdoc.status = :docStatus AND innerhist.newStatus = :historyStatus))
    

    然后对查询调用setParameter("historyStatus", 2)setParameter("docStatus", 1)以获得正确的结果

    就这样

    请注意,我做了一个假设,我们可以使用Historyid属性值作为对象在数据库中放置顺序的指示器