Disons que j'ai un struct:
type User struct {
Name string
Id int
Score int
}
Et une table de base de données avec le même schéma. Quel est le moyen le plus simple d'analyser une ligne de base de données dans une structure? J'ai ajouté une réponse ci-dessous mais je ne suis pas sûr que ce soit la meilleure.
Voici une façon de le faire - assignez simplement toutes les valeurs de structure manuellement dans la fonction Scan
.
func getUser(name string) (*User, error) {
var u User
// this calls sql.Open, etc.
db := getConnection()
// note the below syntax only works for postgres
err := db.QueryRow("SELECT * FROM users WHERE name = $1", name).Scan(&u.Id, &u.Name, &u.Score)
if err != nil {
return &User{}, err
} else {
return &u, nil
}
}
Les tests de paquets donnent souvent des indices sur la façon de faire les choses. Par exemple, de database/sql/sql_test.go
,
func TestQuery(t *testing.T) {
/* . . . */
rows, err := db.Query("SELECT|people|age,name|")
if err != nil {
t.Fatalf("Query: %v", err)
}
type row struct {
age int
name string
}
got := []row{}
for rows.Next() {
var r row
err = rows.Scan(&r.age, &r.name)
if err != nil {
t.Fatalf("Scan: %v", err)
}
got = append(got, r)
}
/* . . . */
}
func TestQueryRow(t *testing.T) {
/* . . . */
var name string
var age int
var birthday time.Time
err := db.QueryRow("SELECT|people|age,name|age=?", 3).Scan(&age)
/* . . . */
}
Ce qui, pour votre question, interroger une ligne dans une structure, se traduirait par quelque chose comme:
var row struct {
age int
name string
}
err = db.QueryRow("SELECT|people|age,name|age=?", 3).Scan(&row.age, &row.name)
Je sais que cela ressemble à votre solution, mais il est important de montrer comment trouver une solution.
Je recommande github.com/jmoiron/sqlx .
Du README:
sqlx est une librairie qui fournit un ensemble d'extensions sur le standard de go
database/sql
bibliothèque. Les versions sqlx desql.DB
,sql.TX
,sql.Stmt
, et al. tous laissent les interfaces sous-jacentes intactes, de sorte que leurs interfaces sont un sur-ensemble sur les standards. Cela rend relativement facile l'intégration de bases de code existantes en utilisant database/sql avec sqlx.Les principaux concepts supplémentaires sont:
- Décalez les lignes dans des structures (avec prise en charge des structures intégrées), des cartes et des tranches
- Prise en charge des paramètres nommés, y compris les instructions préparées
Get
etSelect
pour passer rapidement d'une requête à une structure/une tranche
Le README comprend également un extrait de code montrant le scan d’une ligne dans une structure:
type Place struct {
Country string
City sql.NullString
TelephoneCode int `db:"telcode"`
}
// Loop through rows using only one struct
place := Place{}
rows, err := db.Queryx("SELECT * FROM place")
for rows.Next() {
err := rows.StructScan(&place)
if err != nil {
log.Fatalln(err)
}
fmt.Printf("%#v\n", place)
}
Notez que nous n'avons pas eu à mapper manuellement chaque colonne sur un champ de la structure. sqlx a certains mappages par défaut pour les champs de struct aux colonnes de base de données, ainsi que pour pouvoir spécifier des colonnes de base de données à l'aide de balises (notez le champ TelephoneCode
de la structure Place
ci-dessus). Vous pouvez en savoir plus à ce sujet dans la documentation .
rows, err := connection.Query("SELECT `id`, `username`, `email` FROM `users`")
if err != nil {
panic(err.Error())
}
for rows.Next() {
var user User
if err := rows.Scan(&user.Id, &user.Username, &user.Email); err != nil {
log.Println(err.Error())
}
users = append(users, user)
}
il y a juste un paquet pour ça: sqlstruct
malheureusement, la dernière fois que j'ai vérifié, cela ne supportait pas les structures intégrées (qui sont simples à implémenter vous-même - j'ai eu un prototype fonctionnel en quelques heures).
viens de valider les modifications que j'ai apportées à sqlstruct
Vous pouvez mapper les lignes dans des structures en utilisant github.com/gocraft/dbr
(godoc) .
import (
"github.com/gocraft/dbr"
)
func GetUser(name string) (*User, error) {
var u User
rows, err := db.Query("SELECT * FROM users WHERE name = $1 LIMIT 1", name)
if err != nil {
return nil, err
}
// Load uses reflection to map values into a struct.
n, err := dbr.Load(rows, &u)
if err != nil {
return nil, err
}
if n != 1 {
return nil, NotFound
}
return u, nil
}