我有三个课程相互关联。
最初我在没有分页的情况下构建查询,所有搜索结果都很好。 但现在我需要分页,不想打扰我的初始查询模式。有什么方法可以得到明显的结果。
Class Department{
int id;
String name;
static hasMany = [courses:Courses]
}
Class Courses{
String courseName;
String courseCode;
static hasMany = [student:Student]
static belongsTo = [department:Department]
}
Class Student{
String studentName;
String address;
static belongsTo = [courses:Courses]
}
//controller
def list = Department.createCriteria.listDistinct{
if(params.id){
and{eq{"id",params.id}}
}
and{
courses{
if(params.courseName){
and{eq("courseName",params.courseName)}
}
}
and{
student{
if(params.studentName){
and{eq("studentName",params.studentName)}
}
}
}
}
}
我无法提供实际的表格和域名,但这种关系与上面几乎相同。它对于dintinct结果非常好,但不能分页。我尝试了一些解决方案,但它返回错误。到目前为止我还没有记录任何错误。 我已经知道listDistinct不能用于分页参数。并且列表不提供不同的参数。
我尝试了投影,但无法像之前一样检索所有属性。有什么解决方案吗?因为我需要从所有可能的属性中搜索三个表中任何一个的所有实现。我是否需要将所有查询切换到另一种方法?
答案 0 :(得分:4)
前段时间我遇到类似的任务很困难 - 获得标准,分页和独特的工作,解决方案是: 1.使用list()而不是listDistinct() 2.使用maxResults和firstResult进行分页 3.使用投影{distinct'id'}来获得截然不同的结果 4.在获取id列表后,使用getAll()方法检索实际对象
所以加入它将是:
def ids = Department.createCriteria().list() {
projections {
distinct 'id'
}
maxResults params.max
firstResult params.offset
if(params.id){
and{eq{"id",params.id}}
}
and{
courses{
if(params.courseName){
and{eq("courseName",params.courseName)}
}
}
and{
student{
if(params.studentName){
and{eq("studentName",params.studentName)}
}
}
}
}
}
return Department.getAll(ids)
(代码现未测试)
答案 1 :(得分:0)
listDistinct ()方法不适用于分页选项maxResult和firstResult。如果您需要分页的不同结果,我们目前建议您使用HQL。
答案 2 :(得分:0)
我既不喜欢首先查询完整的ID列表,也不仅仅是一个简单的listDistinct还不够 - 因为我需要能够查询 totalCount 。
我的策略是
我想出了一点 GormHelper :
package foo
import grails.orm.HibernateCriteriaBuilder
import groovy.util.logging.Log4j
import org.codehaus.groovy.grails.web.util.TypeConvertingMap
/**
* Gorm Helper
*
* @param < T >
*/
@Log4j
class GormHelper<T> {
/**
* Clazz the helper will operate on
*/
private final Class clazz
private GormHelper(Class<? extends T> clazz) {
this.clazz = clazz
}
/**
* create a HibernateCriteriaBuilder for the
* specified clazz
* @return
*/
private HibernateCriteriaBuilder createCriteria() {
return clazz.createCriteria()
}
/**
* List objects by conditions
* specified in the closure
* @param params
* @param closure
* @return
*/
List<T> list(Map params, @DelegatesTo(HibernateCriteriaBuilder) Closure closure) {
createCriteria().list(params, closure)
}
/**
* List all objects
* @param params
* @return
*/
List<T> list(Map params = [:]) {
return list(params, {})
}
/**
* apply a closure to a HibernateCriteriaBuilder
* @param crit
* @param closure
*/
public static void apply(HibernateCriteriaBuilder crit, Closure closure) {
if (closure == null) return
closure.rehydrate(crit, crit, crit).call()
}
/**
* List distinct objects
* @param _params
* @param closure
* @return
*/
List<T> listDistinct(Map _params, Closure closure) {
listDistinct(_params, 'id', closure)
}
/**
* List distinct objects
* @param _params
* @param distinctProperty
* @param closure
* @return
*/
List<T> listDistinct(Map _params, String distinctProperty, Closure closure) {
TypeConvertingMap params = new TypeConvertingMap(_params)
// 1st COUNT
Integer total = createCriteria().get {
projections {
countDistinct(distinctProperty)
}
apply(delegate, closure)
} as Integer
// 2nd query distinct items with pagination data
HibernateCriteriaBuilder crit = createCriteria()
List<T> items = crit.listDistinct {
apply(delegate, closure)
setMaxResults(params.int('max'))
setFirstResult(params.int('offset'))
}
// 3rd wrap everything into a PagedResultWrapper
return PagedResultWrapper.wrap(total, items)
}
/**
* Paged Result Wrapper
*
* holds a totalCount beside the data itself
* can be used as a replacement of the PagedResultList
*/
public static class PagedResultWrapper extends LinkedList {
private final Integer total
/**
*
* @param total
* @param list
*/
private PagedResultWrapper(Integer total, List list) {
super()
this.total = total
addAll(list)
}
/**
* wrap results and total into a PagedResultWrapper
* @param total
* @param collection
* @return
*/
public static PagedResultWrapper wrap(Integer total, List collection) {
return new PagedResultWrapper(total, collection)
}
/**
* get the total count
* @return
*/
public int getTotalCount() {
return total.intValue()
}
}
/**
* get a Gorm Helper
* @param clazz
* @return
*/
static <V> GormHelper 'for'(Class clazz, Object owner = null) {
// TODO handle closure ownership
return new GormHelper<V>(clazz)
}
}
你会像这样使用它:
def usersInSelectedGroups = GormHelper.for(User).listDistinct([max: 10, offset: 20]){
groups {
inList('id', [1001, 1002, 1003])
}
}
println "got ${usersInSelectedGroups.totalCount} users"
usersInSelectedGroups.each {println "\t ${it.username}" }
这将输出具有ID 1001,1002,1003 的组中的所有用户 - 如果用户是其中几个组的成员,它们将仅在结果列表中列出一次< / strong> ...