我正在使用Gorm构建Go Web API,作为Amazon RDS中Postgresql数据库的ORM。问题是,尽管数据库中已经填充了数据,但Gorm总是会返回一片全为零的结构。切片中的结构数量适当,具体取决于LIMIT我给的。
LIMIT
我也尝试过使用database/sql内置包直接查询SQL ,在rows.Next()循环内手动插入变量,它没有问题。我用3个不同的表(具有3个不同的结构)尝试了此操作(显然),结果都是相同的。所以我想这在Gorm方面是个问题。该表之一如下所示。
database/sql
rows.Next()
结构结构
type gameCenterLog struct { tm time.Time seq int uid int partner int token sql.NullString bounty int path1 sql.NullString path2 sql.NullString path3 sql.NullString action sql.NullString value1 sql.NullString value2 sql.NullString value3 sql.NullString value4 sql.NullString value5 sql.NullString } func (log *gameCenterLog) TableName() string { return "gamecenter_log" }
Gorm查询的示例
func testGorm() { connString := fmt.Sprintf("host=%v port=%v user=%v password=%v dbname=%v", host, port, user, pass, schema) db, err := gorm.Open("postgres", connString) if err != nil { panic(err.Error()) } defer db.Close() var logs []gameCenterLog today := time.Now().UTC() lastWeek := time.Now().Add(-7 * 24 * time.Hour).UTC() db.Debug().Where("tm BETWEEN ? AND ?", lastWeek, today).Order("tm desc").Limit(limit).Find(&logs) fmt.Printf("Error: %+v\n", db.Error) for _, result := range logs { fmt.Printf("%+v\n", result) } }
政府结果
[2018-08-15 09:57:15] [1429.58ms] SELECT * FROM "gamecenter_log" WHERE (tm BETWEEN '2018-08-08 02:57:14' AND '2018-08-15 02:57:14') ORDER BY tm desc LIMIT 10 [10 rows affected or returned ] Error: <nil> {tm:{wall:0 ext:0 loc:<nil>} seq:0 uid:0 partner:0 token:{String: Valid:false} bounty:0 path1:{String: Valid:false} path2:{String: Valid:false} path3:{String: Valid:false} action:{String: Valid:false} value1:{String: Valid:false} value2:{String: Valid:false} value3:{String: Valid:false} value4:{String: Valid:false} value5:{String: Valid:false}} {tm:{wall:0 ext:0 loc:<nil>} seq:0 uid:0 partner:0 token:{String: Valid:false} bounty:0 path1:{String: Valid:false} path2:{String: Valid:false} path3:{String: Valid:false} action:{String: Valid:false} value1:{String: Valid:false} value2:{String: Valid:false} value3:{String: Valid:false} value4:{String: Valid:false} value5:{String: Valid:false}} {tm:{wall:0 ext:0 loc:<nil>} seq:0 uid:0 partner:0 token:{String: Valid:false} bounty:0 path1:{String: Valid:false} path2:{String: Valid:false} path3:{String: Valid:false} action:{String: Valid:false} value1:{String: Valid:false} value2:{String: Valid:false} value3:{String: Valid:false} value4:{String: Valid:false} value5:{String: Valid:false}} {tm:{wall:0 ext:0 loc:<nil>} seq:0 uid:0 partner:0 token:{String: Valid:false} bounty:0 path1:{String: Valid:false} path2:{String: Valid:false} path3:{String: Valid:false} action:{String: Valid:false} value1:{String: Valid:false} value2:{String: Valid:false} value3:{String: Valid:false} value4:{String: Valid:false} value5:{String: Valid:false}} {tm:{wall:0 ext:0 loc:<nil>} seq:0 uid:0 partner:0 token:{String: Valid:false} bounty:0 path1:{String: Valid:false} path2:{String: Valid:false} path3:{String: Valid:false} action:{String: Valid:false} value1:{String: Valid:false} value2:{String: Valid:false} value3:{String: Valid:false} value4:{String: Valid:false} value5:{String: Valid:false}} {tm:{wall:0 ext:0 loc:<nil>} seq:0 uid:0 partner:0 token:{String: Valid:false} bounty:0 path1:{String: Valid:false} path2:{String: Valid:false} path3:{String: Valid:false} action:{String: Valid:false} value1:{String: Valid:false} value2:{String: Valid:false} value3:{String: Valid:false} value4:{String: Valid:false} value5:{String: Valid:false}} {tm:{wall:0 ext:0 loc:<nil>} seq:0 uid:0 partner:0 token:{String: Valid:false} bounty:0 path1:{String: Valid:false} path2:{String: Valid:false} path3:{String: Valid:false} action:{String: Valid:false} value1:{String: Valid:false} value2:{String: Valid:false} value3:{String: Valid:false} value4:{String: Valid:false} value5:{String: Valid:false}} {tm:{wall:0 ext:0 loc:<nil>} seq:0 uid:0 partner:0 token:{String: Valid:false} bounty:0 path1:{String: Valid:false} path2:{String: Valid:false} path3:{String: Valid:false} action:{String: Valid:false} value1:{String: Valid:false} value2:{String: Valid:false} value3:{String: Valid:false} value4:{String: Valid:false} value5:{String: Valid:false}} {tm:{wall:0 ext:0 loc:<nil>} seq:0 uid:0 partner:0 token:{String: Valid:false} bounty:0 path1:{String: Valid:false} path2:{String: Valid:false} path3:{String: Valid:false} action:{String: Valid:false} value1:{String: Valid:false} value2:{String: Valid:false} value3:{String: Valid:false} value4:{String: Valid:false} value5:{String: Valid:false}} {tm:{wall:0 ext:0 loc:<nil>} seq:0 uid:0 partner:0 token:{String: Valid:false} bounty:0 path1:{String: Valid:false} path2:{String: Valid:false} path3:{String: Valid:false} action:{String: Valid:false} value1:{String: Valid:false} value2:{String: Valid:false} value3:{String: Valid:false} value4:{String: Valid:false} value5:{String: Valid:false}}
请注意,所有结果均为零,结果没有错误…
现在用database/sql
func testSQL() { connString := fmt.Sprintf("host=%v port=%v user=%v password=%v dbname=%v", host, port, user, pass, schema) db, err := sql.Open("postgres", connString) if err != nil { panic(err.Error()) } defer db.Close() today := time.Now().UTC() lastWeek := time.Now().Add(-7 * 24 * time.Hour).UTC() query := fmt.Sprintf("SELECT * FROM \"%v\" WHERE (%v BETWEEN '%d-%02d-%02d %02d:%02d:%02d' AND '%d-%02d-%02d %02d:%02d:%02d') ORDER BY %v LIMIT %v", "gamecenter_log", "tm", lastWeek.Year(), lastWeek.Month(), lastWeek.Day(), lastWeek.Hour(), lastWeek.Minute(), lastWeek.Second(), today.Year(), today.Month(), today.Day(), today.Hour(), today.Minute(), today.Second(), "tm desc", limit) fmt.Println(query) rows, err := db.Query(query) if err != nil { panic(err.Error()) } results := []gameCenterLog{} for rows.Next() { result := gameCenterLog{} err := rows.Scan( &result.tm, &result.seq, &result.uid, &result.partner, &result.token, &result.bounty, &result.path1, &result.path2, &result.path3, &result.action, &result.value1, &result.value2, &result.value3, &result.value4, &result.value5, ) if err != nil { panic(err.Error()) } results = append(results, result) } for _, result := range results { fmt.Printf("%+v\n", result) } }
在这里,我append将result结构手动results切片
append
result
results
原始SQL结果
SELECT * FROM "gamecenter_log" WHERE (tm BETWEEN '2018-08-08 03:03:41' AND '2018-08-15 03:03:41') ORDER BY tm desc LIMIT 10 {tm:{wall:0 ext:63669899021 loc:0xc420113c20} seq:1534276846269 uid:16199265 partner:1 token:{String:1534274713356-bb09968a07 Valid:true} bounty:3 path1:{String:result Valid:true} path2:{String:Win Valid:true} path3:{String: Valid:false} action:{String: Valid:false} value1:{String: Valid:false} value2:{String: Valid:false} value3:{String: Valid:false} value4:{String: Valid:false} value5:{String: Valid:false}} {tm:{wall:0 ext:63669899021 loc:0xc420113c20} seq:1534276846278 uid:16060021 partner:15 token:{String:1534272218332-2a6a0a3263 Valid:true} bounty:2 path1:{String:result Valid:true} path2:{String:Win Valid:true} path3:{String: Valid:false} action:{String: Valid:false} value1:{String:102012 Valid:true} value2:{String:68368886 Valid:true} value3:{String: Valid:false} value4:{String: Valid:false} value5:{String: Valid:false}} {tm:{wall:0 ext:63669899021 loc:0xc420113c20} seq:1534276846275 uid:14565958 partner:6 token:{String:1534277021722-d2f5a72098 Valid:true} bounty:0 path1:{String:track Valid:true} path2:{String:PlayStart Valid:true} path3:{String: Valid:false} action:{String: Valid:false} value1:{String: Valid:false} value2:{String: Valid:false} value3:{String: Valid:false} value4:{String: Valid:false} value5:{String: Valid:false}} {tm:{wall:0 ext:63669899021 loc:0xc420113c20} seq:1534276846279 uid:16060021 partner:15 token:{String:1534272218332-2a6a0a3263 Valid:true} bounty:0 path1:{String:track Valid:true} path2:{String:PlayEnd Valid:true} path3:{String: Valid:false} action:{String: Valid:false} value1:{String:68368886 Valid:true} value2:{String: Valid:false} value3:{String: Valid:false} value4:{String: Valid:false} value5:{String: Valid:false}} {tm:{wall:0 ext:63669899021 loc:0xc420113c20} seq:1534276846268 uid:16199265 partner:1 token:{String:1534274713356-bb09968a07 Valid:true} bounty:0 path1:{String:track Valid:true} path2:{String:PlayEnd Valid:true} path3:{String: Valid:false} action:{String: Valid:false} value1:{String: Valid:false} value2:{String: Valid:false} value3:{String: Valid:false} value4:{String: Valid:false} value5:{String: Valid:false}} {tm:{wall:0 ext:63669899021 loc:0xc420113c20} seq:1534276846270 uid:16199265 partner:1 token:{String:1534274713356-bb09968a07 Valid:true} bounty:0 path1:{String:track Valid:true} path2:{String:Custom Valid:true} path3:{String: Valid:false} action:{String:PemulaGameWin Valid:true} value1:{String:9700600 Valid:true} value2:{String:20000 Valid:true} value3:{String: Valid:false} value4:{String: Valid:false} value5:{String: Valid:false}} {tm:{wall:0 ext:63669899021 loc:0xc420113c20} seq:1534276846280 uid:7627835 partner:15 token:{String:1534256412228-80b0aacd5b Valid:true} bounty:0 path1:{String:track Valid:true} path2:{String:PlayStart Valid:true} path3:{String: Valid:false} action:{String: Valid:false} value1:{String:66729274 Valid:true} value2:{String: Valid:false} value3:{String: Valid:false} value4:{String: Valid:false} value5:{String: Valid:false}} {tm:{wall:0 ext:63669899021 loc:0xc420113c20} seq:1534276846277 uid:10212903 partner:4 token:{String:1534270203280-7875331136 Valid:true} bounty:0 path1:{String:track Valid:true} path2:{String:Custom Valid:true} path3:{String: Valid:false} action:{String:ExpertLose Valid:true} value1:{String:+9.50K Valid:true} value2:{String:5000 Valid:true} value3:{String: Valid:false} value4:{String: Valid:false} value5:{String: Valid:false}} {tm:{wall:0 ext:63669899020 loc:0xc420113c20} seq:1534276846208 uid:13016587 partner:15 token:{String:1534265134142-ed98a488f1 Valid:true} bounty:0 path1:{String:track Valid:true} path2:{String:PlayStart Valid:true} path3:{String: Valid:false} action:{String: Valid:false} value1:{String:67935379 Valid:true} value2:{String: Valid:false} value3:{String: Valid:false} value4:{String: Valid:false} value5:{String: Valid:false}} {tm:{wall:0 ext:63669899020 loc:0xc420113c20} seq:1534276846265 uid:15125780 partner:1 token:{String:1534267652681-cfb8846eae Valid:true} bounty:0 path1:{String:track Valid:true} path2:{String:Custom Valid:true} path3:{String: Valid:false} action:{String:AhliGameLose Valid:true} value1:{String:-1000000 Valid:true} value2:{String:1000000 Valid:true} value3:{String: Valid:false} value4:{String: Valid:false} value5:{String: Valid:false}}
结果出来没问题。
gameCenterlog结构中的所有字段均为小写,因此不会导出。非导出字段对反射不可见,因此Gorm对它们不可见。
gameCenterlog
如果将字段大写:
type gameCenterLog struct { Tm time.Time Seq int Uid int ...
然后Gorm将能够看到它们给出的值。Gorm应该能够弄清楚从PostgreSQL中的列名到Go中的struct字段的映射,但是如果没有,则可以使用gorm:"column:..." struct标记。
gorm:"column:..."