GORM createCriteria и list не возвращают те же результаты: что я могу сделать?

Я использую ловкие и Широ для моих фреймворков безопасности, и я только что столкнулся с ошибкой GORM. Действительно:

User.createCriteria().list { 
   maxResults 10 
} 

возвращает 10 пользователей, тогда как User.list(max: 10) возвращает 9 пользователей !

после дальнейших исследований я узнал, что createCriteria возвращает дважды одного и того же пользователя (admin) потому что администратор имеет 2 роли!!! (Я не шучу).

кажется, что любой пользователь с более чем 1 ролью будет возвращен дважды в createCriteria звонок и User.list вернутся max-1 экземпляры (i.e 9 пользователей вместо 10 пользователей)

какой обходной путь я могу использовать, чтобы вернуть 10 уникальных пользователей ?

это очень раздражает, потому что у меня нет возможности правильно использовать пагинацию.


мои классы домена:

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 
  } 
} 

6 ответов


менее лаконично и ясно, но использование запроса HQL кажется способом решения этой проблемы. Как описано в документация Grails (раздел executeQuery) параметры paginate могут быть добавлены в качестве дополнительных параметров в executeQuery.

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

таким образом, вы все еще можете использовать критерии и передавать в список / параметры разбиения на страницы

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

EDIT: нашел способ получить оба! Полностью собираюсь использовать его сейчас

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

вы будете иметь всю необходимую информацию в хорошем формате PagedResultList!

/ EDIT

к сожалению, я не знаю, как получить комбинацию полных результатов и подмножества Max/offset pagination в одном вызове. (Кто может просветить по этому поводу?)

Я могу, однако, говорить один из способов, который я использовал с успехом, чтобы заставить разбиение на страницы работать вообще в grails.

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
}

это пример того, что я использую, чтобы запустить разбиение на страницы. Как сказал Кок выше, я все еще не понимаю одного атомарного утверждения, которое дает оба результата. Я понимаю, что мой ответ более или менее такой же, как KoK сейчас, извините, но я думаю, что стоит отметить, что rowCount() в проекциях немного более понятен для чтения, и у меня пока нет привилегий комментариев :/

наконец: это Святой Грааль (не каламбур) grails hibernate критерии использования ссылки; закладка его ;) http://www.grails.org/doc/1.3.x/ref/Domain%20Classes/createCriteria.html


оба решения, предлагаемые здесь Рубеном и Аароном, все еще не "полностью" работают для разбиения на страницы поскольку возвращаемый объект (из executeQuery () и listDistinct) является ArrayList (С до max объектов в нем), а не PagedResultList со свойством totalCount заполнено, как я и ожидал ,для" полной " поддержки разбиения на страницы.

предположим, что пример немного сложнее в этом : a. предположим, что роль имеет дополнительный атрибут rolename и b. мы только хотим вернуть distinct Объекты пользователя с ролью.имя роли, содержащее строку " a" (имея в виду, что пользователь может иметь несколько ролей с rolename, содержащим строку "a")

чтобы сделать это с 2 запросами, я должен был бы сделать что-то вроде этого :

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

Это кажется крайне неэффективно.

вопрос: есть ли способ выполнить оба из вышеперечисленных с помощью одного оператора GORM/HQL ?


можно использовать

User.createCriteria().listDistinct {
    maxResults 10
}

Спасибо, что поделились своей проблемой и Kok для ответа на нее. У меня не было возможности переписать его на HQL. Вот мое решение (обходной путь): http://ondrej-kvasnovsky.blogspot.com/2012/01/grails-listdistinct-and-pagination.html

Пожалуйста, скажите мне, если это полезно (по крайней мере для кого-то).