2013-06-23 58 views
30

Hãy nói rằng tôi có một cấu trúc:Làm cách nào để chuyển đổi hàng cơ sở dữ liệu thành cấu trúc, trong Go?

type User struct { 
    Name string 
    Id int 
    Score int 
} 

Và một bảng cơ sở dữ liệu với cùng một giản đồ. Cách dễ nhất để phân tích cú pháp một hàng cơ sở dữ liệu thành một cấu trúc là gì? Tôi đã thêm một câu trả lời dưới đây nhưng tôi không chắc đó là câu trả lời hay nhất.

Trả lời

17

Đây là một cách để thực hiện - chỉ cần gán tất cả các giá trị cấu trúc theo cách thủ công trong hàm 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

sẽ như thế nào mà làm việc cho các giá trị null? – emostafa

+0

@eslammostafa tại điểm nào mã này có thể có vấn đề với giá trị NULL? Ví dụ: – deFreitas

+0

@deFreitas tại điểm số, tôi có nghĩa là các giá trị null đến từ cơ sở dữ liệu. – emostafa

40

Đi kiểm tra gói thường cung cấp manh mối về cách làm việc. Ví dụ, từ 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) 
    /* . . . */ 
} 

Trong đó, đối với câu hỏi của bạn, truy vấn liên tiếp thành một cấu trúc, sẽ dịch một cái gì đó như:

var row struct { 
    age int 
    name string 
} 
err = db.QueryRow("SELECT|people|age,name|age=?", 3).Scan(&row.age, &row.name) 

Tôi biết rằng trông giống như giải pháp của bạn, nhưng nó quan trọng để chỉ cách tìm giải pháp.

+10

nếu cách dễ dàng là gắn các cột vào các trường struct theo cách thủ công. –

+1

Thật không may, điều này không phải là rất thuận tiện đặc biệt là trong trường hợp của cấu trúc lớn hơn - ràng buộc bằng tay để cấu trúc tài sản là thất bại hoàn ... Sử dụng jmoiron/sqlx hoặc một số thư viện khác là hiệu quả hơn ... – shadyyx

+0

tôi tiếp tục nhận được không có gì từ rows.Scan(). tất cả các vars được đặt là rỗng. –

2

có gói chỉ cho rằng: sqlstruct

không may, lần cuối cùng tôi đã kiểm tra nó không hỗ trợ cấu trúc nhúng (mà là tầm thường để thực hiện chính mình - tôi đã có một nguyên mẫu làm việc trong một vài giờ).

chỉ cam kết những thay đổi tôi thực hiện để sqlstruct

0

Bạn có thể lập bản đồ các hàng vào cấu trúc sử dụng 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 

} 
11

Tôi khuyên bạn nên github.com/jmoiron/sqlx.

Từ README:

sqlx là một thư viện cung cấp một tập các phần mở rộng về tiêu chuẩn thư viện database/sql đi của. Phiên bản sqlx của sql.DB, sql.TX, sql.Stmt, et al. tất cả để lại các giao diện cơ bản bị ảnh hưởng, do đó, rằng các giao diện của chúng là một superset trên các tiêu chuẩn. Điều này làm cho tương đối không đau để tích hợp các codebases hiện tại bằng cách sử dụng cơ sở dữ liệu /sql với sqlx.

khái niệm thêm chính gồm có: hàng

  • soái vào cấu trúc (với sự hỗ trợ struct nhúng), bản đồ và lát
  • hỗ trợ tham số được đặt tên bao gồm chuẩn bị phát biểu
  • GetSelect đi một cách nhanh chóng từ truy vấn đến struct/slice

Các README cũng bao gồm một đoạn mã thể hiện quét một hàng vào một cấu trúc:

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) 
} 

Lưu ý rằng chúng tôi không phải tự bản đồ mỗi cột vào một lĩnh vực của cấu trúc. sqlx có một số ánh xạ mặc định cho các trường struct tới các cột cơ sở dữ liệu, cũng như có thể chỉ định các cột cơ sở dữ liệu bằng cách sử dụng các thẻ (lưu ý trường TelephoneCode của cấu trúc Place ở trên). Bạn có thể đọc thêm về điều đó trong the documentation.

+1

cảm ơn bạn về mẹo này! –

1
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) 
} 

Full example

Các vấn đề liên quan