小编典典

go-sql-driver Scan()的命名键

go

使用时go-sql-driver,感觉就像我在重新发明轮子。我习惯于使用具有User与数据库模型严格相关的数据模型(如类)的语言。然后,您当然可以具有要在API上公开的内容的其他模型,但是仍然有数据库对象的模型。在Go中,我不确定如何做到这一点的最佳方法。下面是一个GetUserByEmail功能。

func GetUserByEmail(email string) (*myapp.User, error) {
    smt, err := database.Prepare("SELECT * FROM users WHERE email = ?")

    if err != nil {
        return nil, err
    }

    rows, err := smt.Query(email)
    defer rows.Close()

    if err != nil {
        return nil, err
    }

    var users []*myapp.User

    for rows.Next() {
        var id string
        var confirmed bool
        var password string
        var email string
        var updated string
        var created string
        err = rows.Scan(&id, &confirmed, &password, &email, &updated, &created)

        if err != nil {
            return nil, err
        }

        user := myapp.User{id, confirmed, created, password, email, updated}
        users = append(users, &user)
    }

    if users == nil || len(users) == 0 {
        return nil, errors.New("User not found.")
    }

    if len(users) != 1 {
        return nil, errors.New("Nr of users fetched: " + string(len(users)) + ". Expected: 1.")
    }

    return users[0], nil
}

这里的一个问题是,如果我更改数据库中password和的顺序email,我的应用程序将以静默方式切换它们,并且不会出现任何错误。这是一种可怕的危险行为。可以Scan()以某种方式取得钥匙还是可以其他方式进行?我当然可以查看Columns()并从那里将索引顺序作为一个int(尽管Go似乎没有内置该函数)并将其映射到我的User变量,但是我真的需要对我的所有数据库进行所有这些操作吗?方法?它是抽象的吗?还是我需要自己做?


阅读 301

收藏
2020-07-02

共1个答案

小编典典

这里的一个问题是,如果我更改数据库中密码和电子邮件的顺序,我的应用程序将以静默方式进行切换,并且不会出错。

可以说,解决此问题的最佳方法就是根本不使用SELECT *-始终为您的列命名。问题*实际上可能比您描述的要大-
如果添加新列,您的查询甚至不需要什么?您的代码将无故中断。

但是关于您的更大问题…

可以Scan()以某种方式取得钥匙还是可以其他方式进行?

标准库sql程序包不提供此功能。但是,可以使用第三方库。sqlx可能是最受欢迎的一种,它与标准库最相似。这是我的建议。

如果您更喜欢痛苦,痛苦和永无止境的流血冲突,那么诸如gormgorp之类的事情也是可能的。

2020-07-02