2010-10-11 7 views
7

Używam Nimble i Shiro dla moich frameworków bezpieczeństwa i właśnie przeszedłem przez błąd GORM. Rzeczywiście:GORM createCriteria i lista nie zwracają takich samych wyników: co mogę zrobić?

User.createCriteria().list { 
    maxResults 10 
} 

powraca 10 użytkowników podczas gdy User.list(max: 10) zwraca 9 użytkowników!

Po dalszych badań, okazało się, że createCriteriawraca dwa razy ten sam użytkownik (admin) ponieważ administrator ma 2 role !!! (Nie żartuję).

Wydaje się, że każdy użytkownik z więcej niż 1 roli zostaną zwrócone dwa razy w zaproszeniu createCriteria i User.list powróci max-1 instancji (czyli 9 użytkowników zamiast 10 użytkowników)

Co obejście można użyć w celu zwróciło 10 unikalnych użytkowników?

Jest to bardzo denerwujące, ponieważ nie mam możliwości prawidłowego używania podziału na strony.


moich klas domen są:

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

Jakie jest twoje wdrożenie? Ponieważ mam ten sam problem. Wielkie dzięki –

Odpowiedz

4

Mniej zwięzły i przejrzysty, ale przy użyciu kwerendy HQL wydaje się być sposobem na rozwiązanie tego problemu. Jak opisano w Grails documentation (sekcja executeQuery) parametry stronicowania można dodać jako dodatkowe parametry do executeQuery.

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

Wielkie dzięki. To działa !! Czy wiesz, czy istnieje problem z JIRA dla tego błędu? – fabien7474

+0

Szczegółowe wyjaśnienie, dlaczego listDistinct odfiltrowuje tylko duplikaty w pamięci można znaleźć tutaj w często zadawanych pytaniach dotyczących hibernacji: http://community.jboss.org/wiki/HibernateFAQ-AdvancedProblems#Hibernate_do_w_powrotach_dla_wydarzenia_dla_z_grupy_do_przeszukiwania_w_roszurze – Ruben

0

Można użyć

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

Prawie działa:) ListDistinct zwróci 9 użytkowników zamiast 10 (usunięcie zduplikowanego użytkownika). Ale w jaki sposób mogę użyć takiej strony, na przykład z parametrami przesunięcia. – fabien7474

+0

Może to być pomocne: http://grails.org/doc/latest/api/grails/orm/HibernateCriteriaBuilder.html –

+0

Problem z odrębną projekcją polega na tym, że zachowujesz tylko "kolumny" lub właściwości, w których wyróżnia się określony. – Ruben

3

ten sposób można nadal stosować kryteria i przekazać w liście/stronicowanie paramaters

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

to nie tylko dostarczanie paramatujących paramigłówek, ale także posiadanie prawdziwej PagedResultList z ustawieniem własności totalCount ... – codewandler

1

Oba rozwiązania oferowane tutaj Ruben i Aarona jeszcze nie „w pełni” praca dla paginacji ponieważ Zwracany object (z executeQuery() i listDistinct) jest ArrayList (z maksymalnie maksymalnymi obiektami w nim), a nie PagedResultList z właściwością totalCount wypełnioną tak, jak oczekiwałbym w przypadku "w pełni" obsługi paginacji.

Załóżmy, że przykład jest nieco bardziej skomplikowany: a. Załóżmy, że rola ma dodatkowy atrybut nazwy roli ORAZ b. chcemy tylko zwrócić odrębne obiekty użytkownika za pomocą opcji Role.rolename zawierającej ciąg "a" (pamiętając, że użytkownik może mieć wiele ról z nazwą zawierającą ciąg "a")

Aby to wykonać za pomocą 2 zapytań Musiałbym zrobić coś takiego:

// 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") 
    } 
} 

Wydaje się to rażąco nieefektywne.

Pytanie: czy istnieje sposób na wykonanie obu powyższych z jednym zdaniem GORM/HQL?

+0

możesz użyć idList id w id, zamiast pętli i idEq (it) –

2

EDYCJA: Znaleźć sposób, aby uzyskać oba! Całkowicie zamiar go używać teraz

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 

Będziesz mieć wszystkie potrzebne informacje w ładnym formacie PagedResultList!

/EDIT

Niestety nie wiem jak uzyskać połączenie pełnych wyników i Max/offsetowego stronicowania podzbioru w tej samej rozmowy. (Ktoś, kto może o tym rozjaśnić?)

Mogę jednak mówić w jeden sposób, z którego korzystałem z powodzeniem, aby uzyskać podział na strony w ogóle w grach.

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 
} 

To jest przykład czegoś, czego używam do tworzenia i uruchamiania stronicowania. Tak jak powiedział KoK, wciąż nie mogę znieść pojedynczego oświadczenia atomowego, które daje oba wyniki. Zdaję sobie sprawę, że moja odpowiedź jest mniej więcej taka sama jak teraz KoK, przepraszam, ale myślę, że warto podkreślić, że rowCount() w prognozach jest nieco bardziej czytelny i nie mam jeszcze uprawnień do komentarzy:/

Wreszcie: Jest to święty Graal (gra słów nie przeznaczonych) z hibernacji Kryteria wykorzystania hibernacji odniesienia; dodaj do zakładek;) http://www.grails.org/doc/1.3.x/ref/Domain%20Classes/createCriteria.html

Powiązane problemy