我使用的是Gorm v1。我有这个范围的分页工作正常:
func Paginate(entity BaseEntity, p *Pagination) func(db *gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
var totalRows int64
db.Model(entity).Count(&totalRows)
totalPages := int(math.Ceil(float64(totalRows) / float64(p.PerPage)))
p.TotalPages = totalPages
p.TotalCount = int(totalRows)
p.SetLinks(entity.ResourceName())
return db.Offset(p.Offset).Limit(p.PerPage)
}
}
和我称呼它的方式:
if err := gs.db.Scopes(entities.Paginate(genre, p)).Find(&gs.Genres).Error; err != nil {
return errors.New(err.Error())
}
再次,这曾经正常工作,直到我升级到Gorm v2。现在我得到以下消息:
[0.204ms] [rows:2] SELECT * FROM
genres
LIMITsql:在Scan中期望有9个目标参数,而不是1个;[GIN] 2022/06/18 - 00:41:00 | 400 | 1.5205ms | 127.0.0.1 | GET "/api/v1/genres"错误#01:sql: Scan中预期有9个目标参数,而不是1个;sql:在Scan中期望9个目标参数,而不是1
现在,我发现错误是由于这一行:db.Model(entity).Count(&totalRows)
因为如果我删除它,那么我的查询正在正确执行(显然TotalPages
的数据是不正确的,因为它没有计算)。通过文档,我看到https://gorm.io/docs/method_chaining.html#Multiple-Immediate-Methods所以我的猜测是,用于获得totalRows
的连接被重用,并有一些残余数据,因此我的偏移量和限制查询失败。我试图为计数和偏移查询创建一个新的会话:db.Model(entity).Count(&totalRows).Session(&gorm.Session{})
return db.Offset(p.Offset).Limit(p.PerPage).Session(&gorm.Session{})
希望每个人都使用自己的会话,但似乎不起作用。
有什么建议吗?
万一有人需要的话:
我必须创建一个新的会话,但我没有以正确的方式创建它。我最后做了:
countDBSession := db.Session(&gorm.Session{Initialized: true})
countDBSession.Model(entity).Count(&totalRows)
和预期的一样。现在我的作用域是:
// Paginate is a Gorm scope function.
func Paginate(entity BaseEntity, p *Pagination) func(db *gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
var totalRows int64
// we must create a new session to run the count, otherwise by using the same db connection
// we'll get some residual data which will cause db.Offset(p.Offset).Limit(p.PerPage) to fail.
countDBSession := db.Session(&gorm.Session{Initialized: true})
countDBSession.Model(entity).Count(&totalRows)
totalPages := int(math.Ceil(float64(totalRows) / float64(p.PerPage)))
p.TotalPages = totalPages
p.TotalCount = int(totalRows)
p.SetLinks(entity.ResourceName())
return db.Offset(p.Offset).Limit(p.PerPage)
}
}
请注意,我正在使用一个新的会话来通过countDBSession
获取计数,这不会影响return db.Offset(p.Offset).Limit(p.PerPage).Session(&gorm.Session{})
*db.Gorm
参数的后续使用。