2010-10-11 11 views
7

Estoy usando Nimble y Shiro para mis marcos de seguridad y acabo de encontrar una falla GORM. En efecto:GORM createCriteria y la lista no devuelven los mismos resultados: ¿qué puedo hacer?

User.createCriteria().list { 
    maxResults 10 
} 

vuelve 10 usuarios mientras User.list(max: 10) devuelve 9 usuarios!

Después de nuevas investigaciones, descubrí que createCriteriavuelve dos veces el mismo usuario (admin) porque administrador tiene 2 papeles !!! (No estoy bromeando).

Parece que cualquier usuario con más de 1 función será devuelto dos veces en la llamada createCriteria y User.list volverá max-1 casos (es decir, 9 usuarios en lugar de 10 usuarios)

Qué solución puedo utilizar con el fin de ¿Han devuelto 10 usuarios únicos?

Esto es muy molesto porque no tengo forma de usar la paginación correctamente.


Mis clases de dominio son:

class UserBase { 
    String username 
    static belongsTo = [Role, Group] 
    static hasMany = [roles: Role, groups: Group] 
    static fetchMode = [roles: 'eager', groups: 'eager'] 
    static mapping = { 
    roles cache: true, 
    cascade: 'none', 
    cache usage: 'read-write', include: 'all' 
    } 
} 

class User extends UserBase { 
    static mapping = {cache: 'read-write'} 
} 

class Role { 
    static hasMany = [users: UserBase, groups: Group] 
    static belongsTo = [Group] 
    static mapping = { cache usage: 'read-write', include: 'all' 
    users cache: true 
    groups cache: true 
    } 
} 
+0

¿Cuál es su implementación finalmente? Porque tengo el mismo problema. Muchas gracias –

Respuesta

4

Menos concisa y clara, pero utilizando una consulta HQL parece una manera de resolver este problema. Como se describe en el Grails documentation (sección executeQuery), los parámetros de paginación se pueden agregar como parámetros adicionales para ejecutar Query.

User.executeQuery("select distinct user from User user", [max: 2, offset: 2]) 
+0

Muchas gracias. Funciona !! ¿Sabes si hay un problema JIRA para este error? – fabien7474

+0

Una explicación detallada sobre por qué listDistinct sólo filtra los duplicados en la memoria se puede encontrar aquí en el FAQ de hibernación: http://community.jboss.org/wiki/HibernateFAQ-AdvancedProblems#Hibernate_does_not_return_distinct_results_for_a_query_with_outer_join_fetching_enabled_for_a_collection_even_if_I_use_the_distinct_keyword. – Ruben

0

Puede utilizar

User.createCriteria().listDistinct { 
    maxResults 10 
} 
+0

Casi funcionando:) ListDistinct devolverá 9 usuarios en lugar de 10 (eliminando el usuario duplicado). Pero, ¿cómo puedo usar una paginación así con params de desplazamiento, por ejemplo? – fabien7474

+0

Esto podría ser útil: http://grails.org/doc/latest/api/grails/orm/HibernateCriteriaBuilder.html –

+0

El problema con la proyección distinta es que solo conserva las 'columnas' o propiedades en las que se distingue especificado. – Ruben

3

esta manera puede seguir utilizando criterios y pase lista/paginación Paramaters

User.createCriteria().listDistinct { 
    maxResults(params.max as int) 
    firstResult(params.offset as int) 
    order(params.order, "asc") 
} 
+0

no se trata solo de proporcionar parámetros de paginación, se trata de tener una verdadera PagedResultList con conjunto de propiedades totalCount ... – codewandler

1

Ambas soluciones se ofrecen aquí por Ruben y Aaron todavía no "totalmente" trabajo para paginación porque el vuelto objeto (de executeQuery() y listDistinct) es un ArrayList (con hasta un máximo de objetos en él), y no PagedResultList con la propiedad totalCount poblada como lo esperaría para la paginación de soporte "completamente".

Digamos que el ejemplo es un poco más complicado en eso: a. Asumir que Rol tiene un atributo de nombre de rol adicional AND b. sólo queremos devolver los objetos de usuario con distintos Role.rolename que contiene una cadena "a" (teniendo en cuenta que un usuario podría tener múltiples funciones con nombre de rol que contiene una cadena "a")

para hacer esto con 2 consultas Tendría que hacer algo como esto:

// First get the *unique* ids of Users (as list returns duplicates by 
// default) matching the Role.rolename containing a string "a" criteria 
def idList = User.createCriteria().list { 
    roles { 
    ilike("rolename", "%a%") 
    } 
    projections { 
    distinct ("id") 
    } 
} 

if(idList){ 
    // Then get the PagedResultList for all of those unique ids 
    PagedResultList resultList = 
    User.createCriteria().list(offset:"5", max:"5"){ 
     or { 
     idList.each { 
      idEq(it) 
     } 
     }  
     order ("username", "asc") 
    } 
} 

Esto parece muy ineficiente.

Pregunta: ¿hay alguna forma de lograr ambas cosas con una declaración GORM/HQL?

+0

puede usar 'in' "id" idList en lugar de loop e idEq (it) –

2

EDIT: ¡Encontré una forma de obtener ambos! Totalmente va a usar ahora

http://www.intelligrape.com/blog/tag/pagedresultlist/

If you call createCriteria().list() like this 
def result=SampleDomain.createCriteria().list(max:params.max, offset:params.offset){ 
// multiple/complex restrictions 
    maxResults(params.max) 
    firstResult(params.offset) 
} // Return type is PagedResultList 
println result 
println result.totalCount 

Usted tendrá toda la información que necesita en un formato PagedResultList agradable!

/EDIT

Por desgracia, no sé cómo conseguir una combinación de resultados completos y Max/subconjunto de paginación desplazamiento en la misma llamada. (¿Alguien que puede iluminar sobre eso?)

Sin embargo, puedo hablar de una manera que he usado con éxito para conseguir que la paginación funcione en general en griales.

def numResults = YourDomain.withCriteria() { 
    like(searchField, searchValue) 
    order(sort, order) 
    projections { 
     rowCount() 
    } 
} 

def resultList = YourDomain.withCriteria() { 
    like(searchField, searchValue) 
    order(sort, order) 
    maxResults max as int 
    firstResult offset as int 
} 

Eso es un ejemplo de algo que estoy usando para obtener la paginación en funcionamiento. Como KoK dijo anteriormente, todavía estoy perdido por una sola declaración atómica que arroje los dos resultados. Me doy cuenta de que mi respuesta es más o menos la misma que KoK ahora, lo siento, pero creo que vale la pena señalar que rowCount() en las proyecciones es un poco más claro de leer, y aún no tengo privilegios de comentario:/

Por último: este es el santo grial (sin juego de palabras) de las referencias de uso de criterios de hibernación de Grails; marcarlo como favorito;) http://www.grails.org/doc/1.3.x/ref/Domain%20Classes/createCriteria.html

Cuestiones relacionadas