删除重复记录时分页结果错误
Wrong pagination result when removing duplicate records
我将以下标准与分页参数一起使用。由于加入而产生了一些重复的记录,所以我使用了 setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
。它删除了重复记录,但似乎在应用分页后删除了重复记录。
例如:如果offset为20,max为10,表示应该取20-30条记录。但是假设记录 28,29 和 30 是重复的,所以它们被删除并且在页面中只显示 20-27 条记录。所以第三页只显示 20-27 条记录,即使这些记录不是最后一条。
return Question.createCriteria().list(offset: offset,max: max) {
createAlias("questionHistory","qh")
if(createdStartDate!=null){
ge('createdDate',createdStartDate)
}
if(createdEndDate!=null){
le('createdDate',createdEndDate)
}
if(folderId>0){
eq('folder.id',folderId)
}else if(itemBankId>0){
or{
folders.each {
eq('folder.id',it.id)
}
}
}
....
......
if(authorIds?.size()>0){
'in'("qh.changedBy.id",authorIds)
}
..........
..................
....................................
setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
}
我知道是因为先执行了条件,然后删除了重复的记录。有什么方法可以获取等于找到的重复记录数的下一条记录(如果有的话)?
拼接集合时很难实现分页;另一种方法是使用子查询,如 here.
所述
我已经解决了。我没有在 list() 中使用分页参数,而是使用 setFirstResult/setMaxResults。但缺点是它不提供 'totalCount' 值,因此需要为其触发单独的查询。
解决方案:
setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
setFirstResult(offset)
setMaxResults(max)
它首先删除重复项,然后应用分页给出正确的结果。
遗憾的是,我从未成功完成这项工作。当连接和分页混合在一起时,Hibernate 丢失了,实际上我认为它一定是:AFAIK 解决同一域 class 实例有多行问题的唯一方法是检查域 class 看是否有主键,然后根据主键聚合结果。我不确定这是否总是可行的。
无论如何,我 "solved" 的方法是创建一个单独的查询来评估条件,然后创建一个查询来应用分页(这可以触发另一个查询来计算结果) .
所以使用描述失败案例的要点:https://gist.github.com/deigote/549dcecdbb2a6ba80074
我会通过以下方式解决:
def matchedIds = Car.createCriteria().list([:]) {
distinct 'id'
createAlias('brands', 'brands', CriteriaSpecification.INNER_JOIN)
... // criterias here
}
def actualResults = Car.createCriteria(max: maxResults, first: firstResults).list {
'in'('id', matchedsIds)
}
actualResults
包含当前 "page" 个结果,并允许您调用 totalCount
以获得结果总数。
我将以下标准与分页参数一起使用。由于加入而产生了一些重复的记录,所以我使用了 setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
。它删除了重复记录,但似乎在应用分页后删除了重复记录。
例如:如果offset为20,max为10,表示应该取20-30条记录。但是假设记录 28,29 和 30 是重复的,所以它们被删除并且在页面中只显示 20-27 条记录。所以第三页只显示 20-27 条记录,即使这些记录不是最后一条。
return Question.createCriteria().list(offset: offset,max: max) {
createAlias("questionHistory","qh")
if(createdStartDate!=null){
ge('createdDate',createdStartDate)
}
if(createdEndDate!=null){
le('createdDate',createdEndDate)
}
if(folderId>0){
eq('folder.id',folderId)
}else if(itemBankId>0){
or{
folders.each {
eq('folder.id',it.id)
}
}
}
....
......
if(authorIds?.size()>0){
'in'("qh.changedBy.id",authorIds)
}
..........
..................
....................................
setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
}
我知道是因为先执行了条件,然后删除了重复的记录。有什么方法可以获取等于找到的重复记录数的下一条记录(如果有的话)?
拼接集合时很难实现分页;另一种方法是使用子查询,如 here.
所述我已经解决了。我没有在 list() 中使用分页参数,而是使用 setFirstResult/setMaxResults。但缺点是它不提供 'totalCount' 值,因此需要为其触发单独的查询。
解决方案:
setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
setFirstResult(offset)
setMaxResults(max)
它首先删除重复项,然后应用分页给出正确的结果。
遗憾的是,我从未成功完成这项工作。当连接和分页混合在一起时,Hibernate 丢失了,实际上我认为它一定是:AFAIK 解决同一域 class 实例有多行问题的唯一方法是检查域 class 看是否有主键,然后根据主键聚合结果。我不确定这是否总是可行的。
无论如何,我 "solved" 的方法是创建一个单独的查询来评估条件,然后创建一个查询来应用分页(这可以触发另一个查询来计算结果) .
所以使用描述失败案例的要点:https://gist.github.com/deigote/549dcecdbb2a6ba80074
我会通过以下方式解决:
def matchedIds = Car.createCriteria().list([:]) {
distinct 'id'
createAlias('brands', 'brands', CriteriaSpecification.INNER_JOIN)
... // criterias here
}
def actualResults = Car.createCriteria(max: maxResults, first: firstResults).list {
'in'('id', matchedsIds)
}
actualResults
包含当前 "page" 个结果,并允许您调用 totalCount
以获得结果总数。