showliuzp 2025-11-03 17:08 采纳率: 84.3%
浏览 6
已结题

gorm分页的过程中获取总数


err = query.Limit((*req).PageSize).Offset(((*req).Page - 1) * (*req).PageSize).Find(&list).Count(&count).Error
我在使用gorm的分页和获取总数功能,但以上的Count在最后一页的情况下返回的count为0,我知道以下的方法可以,但会将链式调用分裂,有更好的办法么
err = query.Limit((*req).PageSize).Offset(((*req).Page - 1) * (*req).PageSize).Find(&list).Error
err = query.Count(&count).Error

  • 写回答

4条回答 默认 最新

  • 宝码香车 优质创作者: JavaScript技术领域 2025-11-04 13:18
    关注

    让【宝码香车】来帮您解答,本回答参考DeepSeek编写,并整理提供。

    如果答案让您满意,请采纳、点赞、关注,非常感谢!
    .
    每日一句正能量,让它带给您好心情:阳光总在风雨后,请相信有彩虹。
    .

    在 GORM 中,你遇到的问题是典型的链式调用顺序问题。当你使用 Find(&list).Count(&count) 时,Count 方法实际上是在 Find 查询的结果集上执行,而不是在原始查询上执行。

    推荐的解决方案

    方案1:使用 GORM 的 Scopes 方法(最佳实践)

    func Paginate(page, pageSize int) func(db *gorm.DB) *gorm.DB {
        return func(db *gorm.DB) *gorm.DB {
            offset := (page - 1) * pageSize
            return db.Offset(offset).Limit(pageSize)
        }
    }
    
    
    // 使用方式
    var list []YourModel
    var count int64
    
    
    // 先获取总数
    err = query.Model(&YourModel{}).Count(&count).Error
    if err != nil {
        // 处理错误
    }
    
    
    // 再获取分页数据
    err = query.Scopes(Paginate((*req).Page, (*req).PageSize)).Find(&list).Error
    

    方案2:使用事务保持链式调用

    var list []YourModel
    var count int64
    
    
    err = db.Transaction(func(tx *gorm.DB) error {
        // 获取总数
        if err := tx.Model(&YourModel{}).Count(&count).Error; err != nil {
            return err
        }
        
        // 获取分页数据
        if err := tx.Limit((*req).PageSize).Offset(((*req).Page - 1) * (*req).PageSize).Find(&list).Error; err != nil {
            return err
        }
        
        return nil
    })
    

    方案3:使用结构体封装分页逻辑

    type Pagination struct {
        Page     int
        PageSize int
        Total    int64
        Data     interface{}
    }
    
    
    func (p *Pagination) Paginate(db *gorm.DB, result interface{}) error {
        var count int64
        
        // 获取总数
        if err := db.Model(result).Count(&count).Error; err != nil {
            return err
        }
        p.Total = count
        
        // 获取分页数据
        offset := (p.Page - 1) * p.PageSize
        if err := db.Offset(offset).Limit(p.PageSize).Find(result).Error; err != nil {
            return err
        }
        
        p.Data = result
        return nil
    }
    
    
    // 使用方式
    var list []YourModel
    pagination := &Pagination{
        Page:     (*req).Page,
        PageSize: (*req).PageSize,
    }
    
    
    err = pagination.Paginate(query, &list)
    

    为什么你的原始代码有问题

    // 错误的方式 - Count 在 Find 之后执行
    err = query.Limit(pageSize).Offset(offset).Find(&list).Count(&count).Error
    
    
    // 正确的方式 - 分开执行
    err = query.Limit(pageSize).Offset(offset).Find(&list).Error
    err = query.Count(&count).Error
    

    原因:GORM 的链式调用中,Count 方法会基于前一个查询的结果集进行计数,而不是基于原始查询条件。

    总结

    我推荐使用方案1(Scopes方法),因为:

    • 代码清晰易读
    • 符合 GORM 的设计理念
    • 便于复用分页逻辑
    • 性能最佳

    虽然需要将调用分开,但这实际上是 GORM 分页的最佳实践,能够确保数据的一致性和准确性。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

问题事件

  • 系统已结题 11月13日
  • 已采纳回答 11月5日
  • 创建了问题 11月3日