所以我现在明白了,我为你重新创建并做出了答案
idParent | idChild
---------------
1 | 1
2 | 2
*3 | 1
*3 | 2
所以你追求的真的是 3 或 Ann 吗?
Peter [test.Child : 1]
Joe [test.Child : 2]
Ann [test.Child : 1, test.Child : 2]
你想要的是:
list is [[test.Parent : 3, test.Child : 2, test.Parent : 3, test.Child : 1]]
2016 年 12 月的 E2A 比所有早期版本都要好得多
String query="""select new map(p.name as parentName,
case when (select count(*) from p.children as pc where pc.name in (:children)) >= 2 then 'true'
else 'false' end as childMatch) from Parent p
"""
def inputs=[:]
inputs.children=['Tom','Sam']
def listing = Parent.executeQuery(query,inputs,[readonly:true])
生产:
println "list is $listing"
list is [[childMatch:false, parentName:Peter],
[childMatch:false, parentName:Joe],
[childMatch:true, parentName:Ann]]
现在如果我们简单地改变:
def listing = Parent.executeQuery(query,inputs,[readonly:true])?\
.findAll{it.childMatch=='true'}
println "list is $listing"
list is [[childMatch:true, parentName:Ann]]
您可以看到比以前的方法复杂得多
上面的替代品,但仍然不如上面
您还可以使用in elements 绑定到真实对象而不是您的连接,如下所示:
(:children) in elements(p.children)
但即使使用这种方法,您也会遇到下面讨论的问题。这个答案的第一个方法是相当强大的,使用计数你可以用它作为一种权重的形式来查看有多少记录有 2 多少 1 多少 0 等等,所以更多的用法来自它 -
早期方法
我使用了 hql 并交叉连接:
String query="""from Parent p1 left join p1.children pc1 ,
Parent p left join p.children pc where
pc.name =:input1 and pc1.name= :input2 and
p1.id=p.id group by p.name"""
def inputs=[:]
inputs.input1='Tom'
inputs.input2='Sam'
def list = Parent.executeQuery(query,inputs,[readonly:true])
println "list is ${list}"
但由于所有内容都称为 name,因此如果您想使用 grails groupBy 为每个 parentName 获取更紧凑的列表,则管理起来会有些困难:
String query="""select new map(p1.name as parentName, pc1.name as childName, pc.name as childName2) from Parent p1 left join p1.children pc1 ,
Parent p left join p.children pc where pc.name =:input1 and pc1.name= :input2 and p1.id=p.id """ //group by p1.name, p.name"""
def inputs=[:]
inputs.input1='Tom'
inputs.input2='Sam'
def list = Parent.executeQuery(query,inputs,[readonly:true])
def list1=list.groupBy{it.parentName}
println "list is ${list} vs ${list1}"
像上面那样将这个返回到控制台:
Joe [test.Child : 2]
Ann [test.Child : 2, test.Child : 1]
list is [[childName:Sam, childName2:Tom, parentName:Ann]] vs [Ann:[[childName:Sam, childName2:Tom, parentName:Ann]]]
并且要最终确定这一点,完全取决于您或给定的过程/复杂性,您是否认为该处理应该是原样(可能相当 db 费力与更轻量级的查询以及来自 grails 的一些进一步的查询查找)
// Find all the parents that have 1 of our matches
// Tom but all that also have children greater than 1
def parents = Parent.findAll{children.name=='Tom' && children.size()>1}
//This already returns our only other option 3
println "found ${parents}"
// Now to confirm that the childrens the
// parent has contains our other scenario:
// Lets build our own list from it
def finalList=[]
//Iteration through our listing of parents
parents?.each { Parent p ->
// If the child name matches other case
if (p.children.name.contains('Sam')) {
// add this to our finalList
finalList << p
}
}
// We have correct results in this list
println "we now have ${finalList}"
这可能不会产生巨大的数据库查询交叉连接,但最终对我们感兴趣的每个父母的惰性列表(他们有超过 1 个孩子)进行了大量小型查找
这就是场景 - 我想这取决于您的数据模型以及最适合您的方式。最初的 hql 可能是一个巨大的一次性查询,它产生一个轻量级列表。具有大量轻量级查找的第二个轻量级查询。
第二个例子输出:
found [test.Parent : 3]
we now have [test.Parent : 3]
上面的 finalList 是为了举例说明你将如何手动完成,整个段可以转换为 1 班轮:
def parents = Parent.findAll{children.name=='Tom' && children.size()>1}.collect{[name:it.name, children:it.children]}.findAll{it.children.name.contains('Sam')}
产生:
found [[name:Ann, children:[test.Child : 1, test.Child : 2]]]
VS:
def parents = Parent.findAll{children.name=='Tom' && children.size()>1}.collect{[name:it.name, children:it.children.name]}.findAll{it.children.contains('Sam')}
产生:
found [[name:Ann, children:[Tom, Sam]]]
最后一个示例仅收集特定字段,因此最终的父列表不包含整个子/父对象,而是包含其名称的轻列表。
所以根据需要使用。