go sql驱动程序扫描()的命名键

go sql驱动程序扫描()的命名键,go,Go,当使用go-sql驱动程序时感觉就像我在重新发明轮子一样。我习惯于使用与数据库模型严格相关的数据模型(如用户类)的语言。当然,对于要在API上公开的内容,您可以有额外的模型,但仍然有数据库对象的模型。在围棋中,我不知道怎样才能做到最好。下面是一个GetUserByEmail函数 func GetUserByEmail(email string) (*myapp.User, error) { smt, err := database.Prepare("SELECT * FROM users

当使用
go-sql驱动程序时
感觉就像我在重新发明轮子一样。我习惯于使用与数据库模型严格相关的数据模型(如
用户
类)的语言。当然,对于要在API上公开的内容,您可以有额外的模型,但仍然有数据库对象的模型。在围棋中,我不知道怎样才能做到最好。下面是一个
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
}
这里的一个问题是,如果我更改数据库中
密码
电子邮件
的顺序,我的应用程序将自动切换这些密码,并且不会出现错误。那是一种可怕而危险的行为。
Scan()?当然,我可以查看
Columns()
,然后将索引顺序作为int(尽管Go似乎没有内置该函数)并将其映射到我的
用户
变量,但我真的需要为我的所有数据库方法都这样做吗?它是抽象的还是我需要自己去做

这里的一个问题是,如果我更改数据库中密码和电子邮件的顺序,我的应用程序将自动切换这些密码和电子邮件,并且不会出现错误

可以说,解决这个问题的最好办法就是不要使用
SELECT*
——总是给列命名。
*
的问题实际上可能比您描述的要大——如果添加了新的列,而您的查询甚至不需要这些列,该怎么办?您的代码将中断,没有任何有用的原因

但是关于你更大的问题

Scan()

标准库
sql
包不提供此功能。但是,也有第三方库这样做。可能是最流行的一个,它与标准库最相似。这是我的建议


如果您愿意,可以选择类似或也是可能性。

虽然您回答了这个问题,但我并不认为显式选择解决了问题。您仍然在两个位置(一个在字符串中,另一个在参数中)进行排序,并且这些位置是否必须匹配并不明显,这可能会导致危险的bug。我不打算在Go中使用ORM,但在这之后,我可能不得不(或者自己编写一个包装器,以获得从数据库中获取信息的好方法)。通过在select中使用显式列,可以在同一位置定义两者的顺序(select和驱动程序对select的解释)。是的,这些可能会失去同步,但你正在密切关注相关问题。几乎在所有情况下,这都是正确的方法。。。绝对没有理由使用ORM来解决这个问题(个人观点:永远不要使用ORM,它们总是带来比它们解决的问题更多的问题;但我知道这不是一个共识)
sqlx
应该做您需要的一切。