Golang Gorm scope broken after upgrading from v1 to v2
P粉005417748
P粉005417748 2024-02-03 17:53:53
0
1
495

I am using Gorm v1. My paging range works fine:

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)
    }
}

and how I am called:

if err := gs.db.Scopes(entities.Paginate(genre, p)).Find(&gs.Genres).Error; err != nil {
        return errors.New(err.Error())
    }

Again, this used to work fine until I upgraded to Gorm v2. Now I get the following message:

[0.204ms] [rows: 2] SELECT * FROM genres LIMIT 2 sql: Expected 9 target parameters in scan, not 1; sql: Expected 9 target parameters in scan, instead of 1 [GIN] 2022/06/18 - 00:41:00 | 400 | 1.5205 ms | 127.0 .0.1 | Get "/api/v1/genre" Error #01: sql: Scan expected 9 target parameters instead of 1; sql: Scan expected 9 target parameters instead of 1

Now, I found that the error is caused by this line: db.Model(entity).Count(&totalRows) Because if I remove it, then my query executes correctly (obviously the data for TotalPages is incorrect because it's not calculated). Looking through the docs, I see https://gorm.io/docs/method_chaining.html#Multiple-Immediate-Methods, so my guess is that the connection used to get totalRows is being reused and has some leftovers data so my offset and limit queries are failing. I tried creating a new session for count and offset queries: db.Model(entity).Count(&totalRows).Session(&gorm.Session{})

return db.Offset(p.Offset).Limit(p.PerPage).Session(&gorm.Session{})

Wish everyone could use their own session, but it doesn't seem to work.

Any suggestions?

P粉005417748
P粉005417748

reply all(1)
P粉465287592

If anyone needs it:

I did have to create a new session, but I didn't create it the right way. I ended up doing:

countDBSession := db.Session(&gorm.Session{Initialized: true})
countDBSession.Model(entity).Count(&totalRows)

The effect is as expected. So my current range is:

// 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)
    }
}

Please note that I am using a new session to get the count via countDBSession, this does not affect the *db.Gorm parameters in return db.Offset(p.Offset) .Limit(p.PerPage) usage).Session(&gorm.Session{})

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template