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
应该做您需要的一切。