2013-03-04 90 views
3

HQL noob here,真的很苦恼这个。在HQL中选择集合

可以说我有以下三类:

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问题,但我一定错过了一些东西。预先感谢任何指导。

+0

不是你的问题的直接答案,但问题是你会更好地做更严格的oop,而不是在对象'C'上使用'type',你可以使用列类型的类来添加类的子类型你的数据库作为判别式。那么请求只有正确类型的C才会更容易。 另一方面,我承担了请求过滤集合进入休眠状态的痛苦。 – benzonico 2013-03-04 23:33:56

回答

2

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

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) 

然后,你必须在一个循环在你的名单,这是一个实例的所有元素穿过去,在一个内部循环检查过所有ABC如果该C是所需的类型(仍然必须完成;上面的选择只将选择限制为至少具有一个所需类型的C的选择,但是在您的列表中,这些A具有全部C)并且设置计数为正确的c.id.

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

更好的解决方案是:

与桌下开始你的思维在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' 

A组由C.id的计数你只是通过countA = c.b.size()得到在Java中为每个所选C:或countA = 0; for (B b : c.b) {countA += b.a.size()}(N(1 A和B之间的关系1): A和B之间的1关系)。