2012-06-20 20 views
6

Mam klasy tak:Jak zmusić Groovy/Grails do zwrócenia listy obiektów zamiast listy list obiektów?

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

Kiedy piszę:

Foo.getAll() 

uzyskać listę Foo obiektów tak:

[ Foo1, Foo2, Foo3 ] 

Kiedy piszę:

Foo.getAll().bars 

uzyskać listę list Bar obiektu tak:

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

Ale co chcę to wyjątkowa lista Bar obiektów tak:

[ Bar1, Bar2, Bar3, Bar4 ] 

mój koniec celem jest mieć unikatowy lista identyfikatorów obiektu na liście Bar powyżej, tak:

[ 1, 2, 3, 4 ] 

próbowałem odmiany collect metoda i próbowałem również spread operator, ale nie mam szczęścia.

Odpowiedz

8

przypadku generycznych klas porywające (czyli klas non-Gorm), David jest poprawna korzystanie z flatten i unique jest najlepszym sposobem.

W twoim przykładzie wygląda na to, że używasz obiektów domen GORM w relacji wiele do wielu (w przeciwnym razie nie potrzebujesz ograniczenia unikalności).

Dla klasy domeny najlepiej jest użyć HQL lub kryterium, aby zrobić to w jednym kroku. Dodatkową zaletą jest to, że wygenerowany dla niego SQL jest znacznie bardziej wydajny.

Oto HQL na uzyskanie unikalnych Bar identyfikatory, które są związane z jakimkolwiek Foo w wiele do wielu relacji:

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

kryteria dla tej wyglądałby następująco:

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

Jednym z "problemów" przy stosowaniu tego rodzaju metody jest to, że HQL nie jest obsługiwany w testach jednostkowych (i prawdopodobnie nigdy nie będzie) i Criteria queries with join table projections are broken in 2.0.4 unit tests. Zatem wszelkie testy wokół tego kodu będą wymagały kpiny lub testu integracji.

+1

+1 Jest to najprawdopodobniej najlepszy sposób, aby przejść w tym przypadku :) – epidemian

+0

Tak, zgodził :) – David

+0

Dzięki za wszystkie swoje odpowiedzi facetów. Żałuję, że nie mogłem cię bardziej pochwalić :) Chciałem uniknąć HQL, ale po prawie zakończeniu mojej misji przy użyciu kryteriów, teraz uważam, że paginacja jest ... kłopotliwa. Jeśli nie mogę uzyskać paginacji, aby grać ładnie przy użyciu kryteriów, będę musiał pójść do HQL, myślę. – ubiquibacon

4

Może być lepszy sposób, ale można użyć flatten i unique.

Coś jak:

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

Edit:
Właśnie ponownie przeczytać i zobaczyć, że jesteś po liście identyfikatorów w końcu, nie barów. Jak sugerujesz, użyjesz collect{ it.id }, aby uzyskać identyfikatory. Zrobiłbym to zanim zrobię listę unikalną, ze względu na wydajność.

4

Istnieje metoda Collection#collectMany, która działa tak samo, jak wywołanie collect, a następnie flatten. Aby uzyskać listę Bar identyfikatorów, można zrobić:

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

Zamknięcie { it.bars*.id } zwraca listę z identyfikatorami prętów o Foo (kocham te nazwy zastępcze hehe), a następnie collectMany skleja te wykazy do pojedyncza lista. Jeśli potrzebujesz identyfikatory być unikalne (może Bar może należeć do więcej niż jednej Foo), można dodać do tej wypowiedzi .unique() :)