Подтвердить что ты не робот

Как преобразовать строку базы данных в структуру

Скажем, у меня есть структура:

type User struct {
    Name  string
    Id    int
    Score int
}

И таблица базы данных с той же схемой. Какой самый простой способ проанализировать строку базы данных в структуре? Я добавил ответ ниже, но я не уверен, что он лучший.

4b9b3361

Ответ 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
}