解決Gorm中使用Count后關聯查詢失效的問題
問題描述
當我們 在go中使用gorm進行多表join關聯查詢的時候
如果還有分頁的需求
那么可能會是這樣寫
package mainimport ("gorm.io/driver/mysql""gorm.io/gorm"ormLogger "gorm.io/gorm/logger""time"
)func main() {type Detail struct {UesrId int `json:"user_id"` // 自增 idAge int `json:"age"` // 年齡Email string `json:"email"` // 郵箱}type User struct {Id int `json:"id" gorm:"primaryKey"` // 自增 idName string `json:"name"` // 名字Detail `gorm:"foreignKey:UesrId"`}type MysqlConfig struct {MysqlUrl stringLogger ormLogger.WriterMaxIdleCount intMaxOpen intMaxLifetime time.DurationLogLevel ormLogger.LogLevel}var c MysqlConfigDB, err := gorm.Open(mysql.Open(c.MysqlUrl))if err != nil {panic("GORM 連接失敗," + err.Error())}tx := DB.Model(&User{}).Joins("Detail")var count int64tx.Count(&count)var data []Usertx.Limit(GetLimit()).Offset(GetOffset()).Find(&data)}
這樣count會計算出值,
而 再查詢數據就 會出現數據為空的情況
問題分析:
打印sql出來
SELECT count(*) FROM `users` SELECT `users`.`id`,`users`.`name`,`users`.`uesr_id`,`users`.`age`,`users`.`email` FROM `users` Detail LIMIT 1 OFFSET 3
通過查詢Count方法的源碼我們發現
tx.Statement.AddClause(clause.Select{Expression: clause.Expr{SQL: "count(*)"}})
這里如果調用count方法,gorm會把你的sql的select的字段轉換成 count*
所以,通過join關聯查詢的方式不可以進行對應字段的映射了
解決思路
我們執行查詢和執行記數的tx,使用兩個就好了
因為go語言是引用類型傳遞,所以該怎么進行拷貝tx對象呢
查詢gorm相關源碼發現,session()的源碼里包含
// Session create new db session
func (db *DB) Session(config *Session) *DB {var (txConfig = *db.Configtx = &DB{Config: &txConfig,Statement: db.Statement,Error: db.Error,clone: 1,})if config.Context != nil || config.PrepareStmt || config.SkipHooks {tx.Statement = tx.Statement.clone()tx.Statement.DB = tx}
func (stmt *Statement) clone() *Statement {copy(newStmt.Joins, stmt.Joins)...// 在這里執行了copy方法
}
所以我們可以利用gorm中的session功能深拷貝一個 tx對象,即:tx2 := tx.session()
package mainimport ("gorm.io/driver/mysql""gorm.io/gorm"ormLogger "gorm.io/gorm/logger""time"
)func main() {type Detail struct {UesrId int `json:"user_id"` // 自增 idAge int `json:"age"` // 年齡Email string `json:"email"` // 郵箱}type User struct {Id int `json:"id" gorm:"primaryKey"` // 自增 idName string `json:"name"` // 名字Detail `gorm:"foreignKey:UesrId"`}type MysqlConfig struct {MysqlUrl stringLogger ormLogger.WriterMaxIdleCount intMaxOpen intMaxLifetime time.DurationLogLevel ormLogger.LogLevel}var c MysqlConfigDB, err := gorm.Open(mysql.Open(c.MysqlUrl))if err != nil {panic("GORM 連接失敗," + err.Error())}tx := DB.Model(&User{}).Joins("Detail")tx2 := tx.Session(&gorm.Session{})var count int64tx2.Count(&count)var data []Usertx.Limit(GetLimit()).Offset(GetOffset()).Find(&data)分別打印出內存地址print(tx) // 0x14000282150print(tx2) // 0x140002821e0
}
這樣通過gorm中的session可以深拷貝出一個 gorm對象
執行Count后再執行查詢不會受影響