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