在HQL中选择集合

时间:2013-03-04 20:36:30

标签: hibernate collections hql

这里的HQL noob,真的很难与这个。

假设我有以下三个类:

public class A {
int id;
B b;
}

public class B {
int id;
Set<C> c;
}

public class C {
int id;
String type;
}

表B与C有多对多的关系,由表b_c定义。我需要一个查询,从表A中选择,按C.id排序,按C.type ='desiredType'过滤,并返回C对象和A.id的计数。我一直在玩类似的东西:

SELECT c, COUNT(a.id) as count from A a JOIN a.b.c as c WHERE c.type = 'desiredType' GROUP BY c.id ORDER BY COUNT(a.id) desc

我已经玩过这个查询的不同迭代,但我不断得到各种异常,否则我的查询将不返回任何内容。我似乎不理解的主要问题是如何返回与正确类型匹配的集合的各个对象。

我希望这个问题听起来并不愚蠢。我已经阅读了HQL手册和其他一百个SO问题,但我必须遗漏一些东西。提前感谢任何指导。

1 个答案:

答案 0 :(得分:2)

您想要做的事情不会以这种方式运作。最后你想从A和B中选择,但只选择符合你条件的B.c的子集。这是不可能的。 Hibernate只能加载完整的集合c(不是100%正确,你可以限制你的映射中的选择,但这不是解决方案)。这样就有可能,这可能无法满足您的要求。您加载受exists子句限制的所有A并手动计数:

FROM A a where EXISTS (SELECT 1 FROM C, B_C
                          WHERE C.type = 'desiredType'
                             AND B_C.c_id = C.id
                             AND B_C.b_id = a.b.id)

然后你必须循环遍历列表的所有元素,它们是A的实例,如果C是所需类型,则检查所有abc的内部循环(仍然必须完成;上层) select仅将选择限制为具有至少一个所需类型的C的A,但在列表中,您拥有这些A的所有C)并设置右c.id的计数。

该解决方案的缺点是,即使它们的类型错误,也会加载所有C,并且所有计数都必须在Java代码中完成。所以你可能不喜欢那个解决方案。

更好的解决方案是:

用表C开始思考。在C类中添加Set <B> b;(它是多对多的关系;也许将连接表B_C定义为Java类更方便)。在B类中,您可以添加对表A的访问权限,添加A a(如果B:A是1:1关系)或Set<A> a(如果B:A是1:n关系)。然后你只需选择所需的C:

FROM C WHERE C.type = 'desiredType'

C.id的A组计数您只需通过countA = c.b.size()(A和B之间的1:1关系)或countA = 0; for (B b : c.b) {countA += b.a.size()}(A:1之间的n:1关系)获得每个选定c的Java和B)。