一、問題
在學習beego中出現了Handler crashed with error <Ormer.QueryTable> table name: 'users' not exists
的報錯。
示例程式碼:
models:
func init() {
orm.RegisterModel(new(User))
}
type User struct {
Id int64
Name string
}
controllers:
func (u *UserController) Index() {
var users []models.User
orm.NewOrm().QueryTable("users").All(&users)
fmt.Println(users)
}
二、查詢問題
- 首先找到beego報錯的地方,在
beego/client/orm/orm.go
檔案中QueryTableWithCtx方法。
func (o *ormBase) QueryTableWithCtx(ctx context.Context, ptrStructOrTableName interface{}) (qs QuerySeter) {
var name string
if table, ok := ptrStructOrTableName.(string); ok {
name = nameStrategyMap[defaultNameStrategy](table)
if mi, ok := modelCache.get(name); ok {
qs = newQuerySet(o, mi)
}
} else {
name = getFullName(indirectType(reflect.TypeOf(ptrStructOrTableName)))
if mi, ok := modelCache.getByFullName(name); ok {
qs = newQuerySet(o, mi)
}
}
if qs == nil {
panic(fmt.Errorf("<Ormer.QueryTable> table name: `%s` not exists", name))
}
return
}
ptrStructOrTableName
引數是表名(string
型別),由此判斷是在modelCache.get(name)
出錯,進入其方法:
// get model info by table name
func (mc *_modelCache) get(table string) (mi *modelInfo, ok bool) {
mi, ok = mc.cache[table]
return
}
進一步判斷,傳入的表名不存在_modelCache
,而在在QueryTable
之前僅有orm.RegisterModel(new(User))
是註冊model
方法。
- 追查
orm.RegisterModel
方法最終呼叫的是在beego/client/orm/models.go
中的register方法:
// register register models to model cache
func (mc *_modelCache) register(prefixOrSuffixStr string, prefixOrSuffix bool, models ...interface{}) (err error) {
... // 省略程式碼
for _, model := range models {
...
table := getTableName(val)
if prefixOrSuffixStr != "" {
if prefixOrSuffix {
table = prefixOrSuffixStr + table
} else {
table = table + prefixOrSuffixStr
}
}
...
mi.table = table
mi.pkg = typ.PkgPath()
mi.model = model
mi.manual = true
mc.set(table, mi)
}
return
}
register
方法會先通過getTableName
查詢是否實現TableName
方法,如果實現會直接獲取TableName
返回的表名,然後判斷是否增加字首或者字尾。
// getTableName get struct table name.
// If the struct implement the TableName, then get the result as tablename
// else use the struct name which will apply snakeString.
func getTableName(val reflect.Value) string {
if fun := val.MethodByName("TableName"); fun.IsValid() { // 判斷是否實現TableName方法fun.IsValid()
vals := fun.Call([]reflect.Value{})
// has return and the first val is string
if len(vals) > 0 && vals[0].Kind() == reflect.String {
return vals[0].String()
}
}
return snakeString(reflect.Indirect(val).Type().Name())
}
三、解決方法
通過程式碼的追蹤,發現報錯的原因是QueryTable(”users“)
傳入的引數與註冊的User Model
並不匹配,根據原始碼解決辦法有三種:
修改傳入引數
users
改為user
,並更改資料庫中的表名orm.NewOrm().QueryTable("user").All(&users)
在
User Model
中實現TableName
方法func (u *User) TableName() string { return "users" }
註冊model時使用字尾
orm.RegisterModelWithSuffix("s", new(User))
四、總結
1、beego中QueryTable
方法中表名引數是與註冊Model
相關聯的。
2、如果資料庫中表名和Model
名稱不相同時,可使用實現TableName
方法或者註冊model
時新增字首RegisterModelWithPrefix
、新增字尾RegisterModelWithSuffix
時註冊實際表名。
本作品採用《CC 協議》,轉載必須註明作者和本文連結