2012-06-20 54 views
6

que tienen una clase como esta:¿Cómo hacer que Groovy/Grails devuelva una Lista de objetos en lugar de una Lista de Listas de objetos?

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

Cuando escribo:

Foo.getAll() 

puedo obtener una lista de Foo objetos de esta manera:

[ Foo1, Foo2, Foo3 ] 

cuando escribo:

Foo.getAll().bars 

consigo una lista de listas de Bar objeto como éste:

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

Pero lo que yo quiero es una lista única de Bar objetos de esta manera:

[ Bar1, Bar2, Bar3, Bar4 ] 

Mi objetivo final es tener un único lista de identificadores de objeto Bar en la lista anterior, así:

[ 1, 2, 3, 4 ] 

he intentado variaciones del collect método y también he probado el spread operator pero no estoy teniendo suerte.

Respuesta

8

Para clases groovy genéricas (es decir, clases no GORM), David tiene razón que usar flatten y unique es la mejor manera de hacerlo.

En su ejemplo, parece que está utilizando objetos de dominio GORM en una relación muchos a muchos (de lo contrario, no necesitaría la restricción de exclusividad).

Para una clase de dominio, lo mejor es utilizar HQL o un criterio para hacerlo en un solo paso. Una ventaja adicional es que el SQL generado para él es mucho más eficiente.

Aquí está el HQL para conseguir los únicos Bar los identificadores que se relacionan con cualquier Foo en una relación de muchos a muchos:

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

Los criterios para este sería el resultado:

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

Un "problema" con el uso de este tipo de método es que HQL no es compatible con las pruebas unitarias (y probablemente nunca lo sea) y Criteria queries with join table projections are broken in 2.0.4 unit tests. Entonces cualquier prueba alrededor de este código necesitaría ser burlada o usar una prueba de integración.

+1

+1 Esta es probablemente la mejor manera de proceder en este caso :) – epidemian

+0

Sí, estoy de acuerdo :) – David

+0

Gracias por todas sus respuestas chicos. Desearía poder haberte ganado un voto más :) Quise evitar HQL, pero casi habiendo completado mi búsqueda usando criterios, ahora encuentro que la paginación es ... problemática. Si no puedo obtener la paginación para jugar bien usando criterios, tendré que ir a HQL, creo. – ubiquibacon

4

Puede haber una manera mejor, pero puede usar flatten y unique.

Algo así como:

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

Editar:
acabo de volver a leer y ver que usted está después de una lista de ID al final, no las barras. Como sugirió, usaría collect{ it.id } para obtener los ID. Lo haría antes de hacer que la lista sea única, por motivos de rendimiento.

4

Hay un método Collection#collectMany que funciona de la misma manera que llamando al collect y luego al flatten. Para obtener la lista de ID de barras, es posible hacer:

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

El cierre { it.bars*.id } devuelve una lista con los ID de los barrotes de una Foo (me encanta estos nombres de marcador de posición jeje), y luego collectMany concatena estas listas en una sola lista. Si necesita que los ID sean únicos (tal vez un Bar puede pertenecer a más de un Foo), puede agregar un .unique() a esa expresión :)

Cuestiones relacionadas