Grails 命名查询:查找 child A 和 child B 的 parents
Grails named queries: find parents of child A and child B
我有这个:
class Parent {
String name
static hasMany = [children: Child]
}
class Child {
String name
}
我想找到所有 parents 中有一个名为 "Tom" 的 child 和另一个名为 "Sam" 的 child。
id | parentName
---------------
1 | Peter
2 | Joe
3 | Ann
id | childName
---------------
1 | Tom
2 | Sam
idParent | idChild
---------------
1 | 1
2 | 2
3 | 1
3 | 2
在示例中,它将是 Ann。
我试过这个:
static namedQueries = {
findParents{nameList ->
children{
nameList.each{childName->
and{
ilike('nombre', '%'+childName+'%')
}
}
}
但通过这种方式,我只搜索了一个 child 名字中有 Tom 和 Sam 的人。在示例中,它将 return 什么都没有。
我曾尝试使用 'in' 'name', ["Tom","Sam"]
而不是 ilike 运算符,但现在我将使用名为 "Tom" 的 child 或名为 child 的所有 parents "Sam"。在示例中,它将 return Peter、Joe 和 Ann
有什么想法吗?
提前致谢!
所以我现在明白了,我重新创建并为你做了一个答案
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]]
E2A Dec 2016 比所有早期版本都好得多的方法
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
绑定到真正的 object 而不是像下面这样的连接:
(: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}"
但是因为所有的东西都被称为名字,如果你想使用 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}"
像上面的 returns 这个到控制台:
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 费力 vs 更轻量级查询和来自 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}"
这可能不会产生巨大的数据库查询交叉连接,但最终再次对我们感兴趣的每个 parent 的惰性列表进行了很多小查找(谁有超过 1 child)
这是场景 - 我想这取决于您的数据模型以及最适合您的数据模型。最初的 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]]]
对比:
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]]]
最后一个示例仅收集特定字段,因此最终 parents 列表不包含整个 child/parent objects,而是包含其名称的简单列表。
所以按需使用。
我有这个:
class Parent {
String name
static hasMany = [children: Child]
}
class Child {
String name
}
我想找到所有 parents 中有一个名为 "Tom" 的 child 和另一个名为 "Sam" 的 child。
id | parentName
---------------
1 | Peter
2 | Joe
3 | Ann
id | childName
---------------
1 | Tom
2 | Sam
idParent | idChild
---------------
1 | 1
2 | 2
3 | 1
3 | 2
在示例中,它将是 Ann。
我试过这个:
static namedQueries = {
findParents{nameList ->
children{
nameList.each{childName->
and{
ilike('nombre', '%'+childName+'%')
}
}
}
但通过这种方式,我只搜索了一个 child 名字中有 Tom 和 Sam 的人。在示例中,它将 return 什么都没有。
我曾尝试使用 'in' 'name', ["Tom","Sam"]
而不是 ilike 运算符,但现在我将使用名为 "Tom" 的 child 或名为 child 的所有 parents "Sam"。在示例中,它将 return Peter、Joe 和 Ann
有什么想法吗?
提前致谢!
所以我现在明白了,我重新创建并为你做了一个答案
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]]
E2A Dec 2016 比所有早期版本都好得多的方法
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
绑定到真正的 object 而不是像下面这样的连接:
(: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}"
但是因为所有的东西都被称为名字,如果你想使用 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}"
像上面的 returns 这个到控制台:
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 费力 vs 更轻量级查询和来自 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}"
这可能不会产生巨大的数据库查询交叉连接,但最终再次对我们感兴趣的每个 parent 的惰性列表进行了很多小查找(谁有超过 1 child)
这是场景 - 我想这取决于您的数据模型以及最适合您的数据模型。最初的 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]]]
对比:
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]]]
最后一个示例仅收集特定字段,因此最终 parents 列表不包含整个 child/parent objects,而是包含其名称的简单列表。
所以按需使用。