gorm のRecordNotFoundがsliceで結果を受け取ると必ずfalseになる件
書いた経緯
GoのORMの一つであるgorm。
使っていて盛大にどハマりして、結局gormのソースを読むことになったのでその備忘
RecordNotFoundって何奴?
gormのリファレンスを見ると以下の感じです。
func (s *DB) RecordNotFound() bool
RecordNotFound check if returning ErrRecordNotFound error
ふむふむ。文面だけ読むとレコードがないエラーがあるかをチェックするらしい。
実際にソースにすると以下です。
main.go
type user struct {
ID int `gorm:"column:id"`
Name string `gorm:"column:name"`
}
func main(){
db, _ := gorm.Open("mysql", "root@tcp(127.0.0.1:3306)/playground")
result := user{}
recordNotFound := db.Table("user").First(&result).RecordNotFound()
}
接続情報やらエラー処理やらを色々説明をすっ飛ばしますが、上記のように書けます
で、この場合は、レコードがないときはtrueを返してくれます
ちなみに,userテーブルの中身は空っぽでidとnameのカラムがあります。
さて、本題
以下の時の結果は果たしてどうなるでしょうか?
main.go
package main
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
type user struct {
ID int `gorm:"column:id"`
Name string `gorm:"column:name"`
}
func main() {
db, _ := gorm.Open("mysql", "root@tcp(127.0.0.1:3306)/playground")
result := user{}
recordNotFound := db.Table("user").First(&result).RecordNotFound()
fmt.Print("structのとき=")
fmt.Println(recordNotFound)
resultSlice := []user{}
recordNotFound = db.Table("user").First(&resultSlice).RecordNotFound()
fmt.Print("sliceのとき=")
fmt.Println(recordNotFound)
}
実行結果
$ go run main.go
recordNotFoundがstructのとき=true
recordNotFoundがsliceのとき=false
...実行結果が違う...だと。
そうです。slice型の時はRecordNotFoundエラーはなし。
gormのソースを見ると確かに,0件かつ、sliceでないときにエラーを格納しています。
callback_query.go
//~~省略~~
if err := rows.Err(); err != nil {
scope.Err(err)
} else if scope.db.RowsAffected == 0 && !isSlice {
scope.Err(ErrRecordNotFound)
}
//~~省略~~
まとめ
結果があるかどうかを見たい時は
len(result) > 0
とする必要がある。
これに関する議論はissuesで語られており、
意識してこの形にしているみたいです。