Как преобразовать строку базы данных в структуру
Скажем, у меня есть структура:
type User struct {
Name string
Id int
Score int
}
И таблица базы данных с той же схемой. Какой самый простой способ проанализировать строку базы данных в структуре? Я добавил ответ ниже, но я не уверен, что он лучший.
Ответы
Ответ 1
Здесь один из способов сделать это - просто назначьте все значения структуры вручную в функции 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
}
}
Ответ 2
Пакетные тесты часто дают подсказки о том, как что-то делать. Например, из 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)
/* . . . */
}
Что, на ваш вопрос, запрос строки в структуру, будет означать что-то вроде:
var row struct {
age int
name string
}
err = db.QueryRow("SELECT|people|age,name|age=?", 3).Scan(&row.age, &row.name)
Я знаю, что это похоже на ваше решение, но важно показать, как найти решение.
Ответ 3
Я рекомендую github.com/jmoiron/sqlx.
Из README:
sqlx - это библиотека, которая предоставляет набор расширений на стандарте go database/sql
библиотека. Версия sqlx sql.DB
, sql.TX
, sql.Stmt
, et al. все оставят базовые интерфейсы нетронутыми, поэтому что их интерфейсы являются надмножеством на стандартных. Это делает относительно безболезненно интегрировать существующие кодовые базы, используя база данных /sql с sqlx.
Основные дополнительные понятия:
- Маршал строит в структуры (со встроенной поддержкой структуры), карты и срезы
- Поддержка именованных параметров, включая подготовленные операторы
-
Get
и Select
быстро перейти от запроса к struct/slice
README также включает фрагмент кода, демонстрирующий сканирование строки в struct:
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)
}
Обратите внимание, что нам не приходилось вручную сопоставлять каждый столбец с полем структуры. sqlx имеет некоторые сопоставления по умолчанию для столбцов структуры для столбцов базы данных, а также возможность указывать столбцы базы данных с использованием тегов (обратите внимание на поле TelephoneCode
структуры Place
выше). Подробнее об этом можно узнать в документации.
Ответ 4
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)
}
Полный пример
Ответ 5
там пакет только для этого: sqlstruct
К сожалению, в прошлый раз, когда я проверил, он не поддерживал встроенные структуры (которые тривиальны для реализации - у меня был рабочий прототип через несколько часов).
просто зафиксировал изменения, которые я сделал для sqlstruct
Ответ 6
Вы можете сопоставить строки в структурах, используя 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
}
Ответ 7
использовать:
Go-модель-MySQL
sqlbuilder
val, err = m.ScanRowType(row, (*UserTb)(nil))
или полный код
import (
"database/sql"
"fmt"
lib "github.com/eehsiao/go-models-lib"
mysql "github.com/eehsiao/go-models-mysql"
)
// MyUserDao : extend from mysql.Dao
type MyUserDao struct {
*mysql.Dao
}
// UserTb : sql table struct that to store into mysql
type UserTb struct {
Name sql.NullString 'TbField:"Name"'
Id int 'TbField:"Id"'
Score int 'TbField:"Score"'
}
// GetFirstUser : this is a data logical function, you can write more logical in there
// sample data logical function to get the first user
func (m *MyUserDao) GetFirstUser() (user *User, err error) {
m.Select("Name", "Id", "Score").From("user").Limit(1)
fmt.Println("GetFirstUser", m.BuildSelectSQL().BuildedSQL())
var (
val interface{}
row *sql.Row
)
if row, err = m.GetRow(); err == nil {
if val, err = m.ScanRowType(row, (*UserTb)(nil)); err == nil {
u, _ := val.(*UserTb)
user = &User{
Name: lib.Iif(u.Name.Valid, u.Nae.String, "").(string),
Id: u.Id,
Score: u.Score,
}
}
}
row, val = nil, nil
return
}