2012-06-20 5 views
6

У меня есть класс, как это:Как сделать Groovy/Grails возвращать список объектов вместо списка списков объектов?

class Foo { 
    static hasMany = [bars: Bar] 
} 

Когда я пишу:

Foo.getAll() 

Я получаю список Foo объектов, как это:

[ Foo1, Foo2, Foo3 ] 

Когда я пишу:

Foo.getAll().bars 

получить список списков Bar объекта, как это:

[ [ Bar1, Bar2 ], [ Bar2, Bar3 ], [ Bar1, Bar4 ] ] 

Но то, что я хочу, это уникальный список Bar объектов, как это:

[ Bar1, Bar2, Bar3, Bar4 ] 

Моя конечная цель должна иметь уникальный список идентификаторов в Bar объекта в списке выше, например:

[ 1, 2, 3, 4 ] 

Я попытался вариации collect, и я также попробовал spread operator, но мне не повезло.

ответ

8

Для общих классов groovy (т.е. классов, отличных от GORM), Дэвид прав что использование flatten и unique - лучший способ пойти.

В вашем примере, однако, похоже, что вы используете объекты домена GORM в отношениях «многие ко многим» (иначе вам не понадобится ограничение уникальности).

Для класса домена вам лучше всего использовать либо HQL, либо критерии, чтобы сделать это за один шаг. Дополнительным преимуществом является то, что созданный для него SQL намного эффективнее.

Вот HQL для получения уникальных Bar идентификаторов, которые относятся к любому Foo в многие-ко-многим:

Bar.executeQuery("select distinct b.id from Foo f join f.bars b") 

Критерии для этого будет выглядеть следующим образом:

Foo.withCriteria { 
    bars { 
     projections { 
      distinct("id") 
     } 
    } 
} 

Одна «проблема» с использованием такого метода заключается в том, что HQL не поддерживается в модульных тестах (и, вероятно, никогда не будет) и Criteria queries with join table projections are broken in 2.0.4 unit tests. Таким образом, любые тесты вокруг этого кода либо должны быть издевательствами, либо использовать интеграционный тест.

+1

+1 Это, скорее всего, лучший способ пойти в этом случае :) – epidemian

+0

Да, согласился :) – David

+0

Спасибо за все ваши ответы. Хотелось бы, чтобы я смог вытащить вас всех больше :) Я хотел избежать HQL, но, почти выполнив свой квест с использованием критериев, теперь я считаю, что разбиение на страницы ... беспокойно. Если я не могу получить разбиение на страницы, чтобы играть хорошо, используя критерии, мне придется идти на HQL, я думаю. – ubiquibacon

4

Возможно, будет лучший способ, но вы можете использовать flatten и unique.

Что-то вроде:

def allBars = Foo.getAll().bars.flatten().unique()

Edit:
Я просто перечитать и посмотреть, что вы после списка идентификаторов в конце концов, не Барс. Как вы сказали, вы должны использовать collect{ it.id } для получения идентификаторов. Я сделал бы это, прежде чем сделать список уникальным, по соображениям производительности.

4

Существует метод Collection#collectMany, который работает так же, как и для вызова collect, а затем flatten. Чтобы получить список идентификаторов бара, вы можете сделать:

def barIds = Foo.getAll().collectMany { it.bars*.id } 

{ it.bars*.id } закрытие возвращает список с идентификаторами запоров Foo (я люблю эти имена заполнителей хеха), а затем collectMany присоединяет эти списки в один список. Если вам нужно, чтобы идентификаторы были уникальными (может быть, Бар может принадлежать более чем одному Foo), вы можете добавить .unique() к этому выражению :)