Итак, теперь я понимаю, и я воссоздал и сделал ответ для вас
idParent | idChild
---------------
1 | 1
2 | 2
*3 | 1
*3 | 2
Так что на самом деле вы ищете 3 или Энн, верно?
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, декабрь 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
, который привязывается к реальному объекту, а не к вашему соединению, как показано ниже:
(: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]]]
И, чтобы закончить на этом этапе, это полностью зависит от вас или данного процесса/сложности в том, считаете ли вы, что эта обработка должна быть такой, какая она есть (может быть, довольно напряженная БД по сравнению с более легким запросом и некоторым дополнительным запросом от Грааля с легким поиском)
// 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 может быть огромным одноразовым запросом, который создает легкий список. 2-й легкий запрос с большим количеством легких поисков.
Второй пример выводит:
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]]]
В самом последнем примере собираются только определенные поля, поэтому окончательный список родителей содержит не целые дочерние/родительские объекты, а упрощенный список, содержащий их имена.
Так что используйте по мере необходимости.
person
V H
schedule
25.10.2016