Home  >  Q&A  >  body text

Golang Gorm scope broken after upgrading from v1 to v2

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粉005417748P粉005417748259 days ago465

reply all(1)I'll reply

  • P粉465287592

    P粉4652875922024-02-04 17:11:07

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

    reply
    0
  • Cancelreply