GORM createCriteria和list不会返回相同的结果:我该怎么办?

时间:2010-10-11 10:46:29

标签: grails gorm shiro nimble

我正在使用NimbleShiro作为我的安全框架,而我刚刚遇到GORM错误。确实:

User.createCriteria().list { 
   maxResults 10 
} 

返回 10个用户,而User.list(max: 10)返回 9个用户

经过进一步调查,我发现createCriteria 返回同一用户的两倍(管理员),因为管理员有2个角色 !!! (我不是在开玩笑。)

似乎任何具有多于1个角色的用户将在createCriteria调用中返回两次,而User.list将返回max-1个实例(即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 个答案:

答案 0 :(得分:4)

简洁明了,但使用HQL查询似乎是解决此问题的一种方法。如Grails documentation(executeQuery部分)中所述,可以将paginate参数作为额外参数添加到executeQuery中。

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

答案 1 :(得分:3)

这样你仍然可以使用标准并传入列表/分页参数

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

答案 2 :(得分:2)

编辑:找到一种方法来获得两者!现在完全使用它

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

不幸的是,我不知道如何在同一个调用中获得完整结果和最大/偏移分页子集的组合。 (任何可以启发的人?)

然而,我可以用一种方式来说明我在成功时使用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上面所说的那样,我仍然对单个原子声明感到茫然,这个声明给出了两个结果。我意识到我的答案或多或少与KoK相同,对不起,但我认为值得指出的是,投影中的rowCount()稍微清楚一点,我还没有评论权限:/

最后:这是grails hibernate标准用法参考的圣杯(没有双关语);给它添加书签;) http://www.grails.org/doc/1.3.x/ref/Domain%20Classes/createCriteria.html

答案 3 :(得分:1)

Ruben和Aaron在这里提供的两种解决方案仍然没有“完全”用于分页 因为返回的对象(来自executeQuery()和listDistinct)是一个ArrayList (最多包含最大对象),而不是具有totalCount属性的PagedResultList 正如我所期望的那样填充“完全”支持分页。

让我们说这个例子有点复杂: 一个。假设Role具有另外的rolename属性AND 湾我们只希望返回包含字符串“a”的Role.rolename的不同User对象 (请记住,用户可能有多个角色,其角色名称包含字符串“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语句完成上述两个步骤?

答案 4 :(得分:0)

您可以使用

User.createCriteria().listDistinct {
    maxResults 10
}

答案 5 :(得分:0)

感谢您分享您的问题和Kok回答它。我没有机会将它重写为HQL。这是我的解决方案(解决方法):http://ondrej-kvasnovsky.blogspot.com/2012/01/grails-listdistinct-and-pagination.html

请告诉我这是否有用(至少对某人而言)。