Grails命名查询:找到孩子A和孩子B的父母

时间:2016-10-24 13:02:44

标签: grails criteria named-query

我有这个:

class Parent {
  String name
  static hasMany = [children: Child]
}

class Child {
  String name
}

我想找到所有有孩子的父母,他们的名字叫汤姆"另一个名叫" Sam"。

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+'%')                 
                    }
            }           
     }

但是这样我只能找到一个名叫汤姆和萨姆的孩子。在示例中,它将不返回任何内容。

我曾尝试使用'in' 'name', ["Tom","Sam"]代替ilike运营商,但现在我会让所有父母都有一个名叫" Tom"或者是一个名叫" Sam"的孩子。在这个例子中,它将返回Peter,Joe和Ann

有什么想法吗?

提前致谢!

1 个答案:

答案 0 :(得分:1)

所以我现在明白了,我重新创造并为你找到答案

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和cross join:

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}"

如上所述将其返回到控制台:

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]]]

并且最后确定这一点,完全取决于你或者给定的过程/复杂性,你是否认为这个处理应该是这样(对于更轻量级的查询和从光的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]]]

最后一个示例仅收集特定字段,因此最终父项列表不包含完整的子/父对象,而是包含其名称的灯光列表。

因此请按要求使用。