beego报错 table name: `xxx` not exists

一、问题

在学习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)
}

二、查找问题

  1. 首先找到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方法。

  1. 追查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并不匹配,根据源码解决办法有三种:

  1. 修改传入参数users改为user,并更改数据库中的表名

    orm.NewOrm().QueryTable("user").All(&users)
  2. User Model中实现TableName方法

    func (u *User) TableName() string {
     return "users"
    }
  3. 注册model时使用后缀

    orm.RegisterModelWithSuffix("s", new(User))

四、总结

1、beego中QueryTable方法中表名参数是与注册Model相关联的。

2、如果数据库中表名和Model名称不相同时,可使用实现TableName方法或者注册model时添加前缀RegisterModelWithPrefix、添加后缀RegisterModelWithSuffix时注册实际表名。

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!