第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機(jī)立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何在 Go DRY 中掃描數(shù)據(jù)庫行?

如何在 Go DRY 中掃描數(shù)據(jù)庫行?

Go
慕容森 2023-05-08 14:39:21
我在數(shù)據(jù)庫中有一個包含用戶帳戶信息的表。我有一個名為用戶定義的結(jié)構(gòu)。type User struct {  Id        uint  Username  string  Password  string  FirstName string  LastName  string  Address1  string  Address2  string  .... a bunch more fields ...}為了獲取個人用戶帳戶,我定義了一個方法func (user *User) GetById(db *sql.DB, id uint) error {  query := `SELECT             ...a whole bunch of SQL ...            WHERE id = $1            ... more SQL ...            LIMIT 1`  row := db.QueryRow(query, id)  err := row.Scan(    &user.Id,    &user.UserName,    &user.Password,    &user.FirstName,    &user.LastName,    ... some 20 more lines of fields read into the struct ...  )  if err != nil {    return err  }  return nil}在系統(tǒng)中有幾個地方我需要獲取用戶信息作為更大查詢的一部分。也就是說,我正在獲取一些其他類型的對象,還有一個與之相關(guān)的用戶帳戶。這意味著,我必須rows.Scan(&user.Username, &user...)一遍又一遍地重復(fù)整個過程,這會占用整個頁面,而且很容易出錯,如果我更改了用戶表結(jié)構(gòu),我將不得不更改很多地方的代碼。我怎樣才能讓它更干燥?編輯:我不確定為什么將其標(biāo)記為重復(fù),但由于需要進(jìn)行此編輯,我將嘗試再解釋一次。我不是在問如何將一行掃描到一個結(jié)構(gòu)中。正如上面的代碼清楚地顯示的那樣,我已經(jīng)知道該怎么做。我在問如何構(gòu)建結(jié)構(gòu)掃描代碼,這樣我就不必每次掃描相同類型的結(jié)構(gòu)時都重復(fù)掃描代碼的同一頁。編輯:另外,是的,我知道 sqlstruct 和 sqlx 以及類似的庫。我故意避免這些,因?yàn)樗鼈円蕾囉?reflect 包,并有詳細(xì)記錄的性能問題。我打算使用這些技術(shù)潛在地掃描數(shù)百萬行(不是數(shù)百萬用戶,但這個問題擴(kuò)展到其他記錄類型)。編輯:所以,是的,我知道我應(yīng)該寫一個函數(shù)。我不確定這個函數(shù)應(yīng)該將什么作為參數(shù)以及它應(yīng)該返回什么結(jié)果。可以說我想要容納的另一個查詢看起來像這樣SELECT    s.id,    s.name,    ... more site fields ...    u.id,    u.username,    ... more user fields ...FROM site AS sJOIN user AS u ON (u.id = s.user_id)JOIN some_other_table AS st1 ON (site.id = st1.site_id)... more SQL ...我有一個嵌入用戶結(jié)構(gòu)的站點(diǎn)結(jié)構(gòu)方法。這里不想重復(fù)用戶掃碼。我想調(diào)用一個函數(shù),它將 raw 的用戶部分掃描到用戶結(jié)構(gòu)中,就像在上面的用戶方法中一樣。
查看完整描述

1 回答

?
莫回?zé)o

TA貢獻(xiàn)1865條經(jīng)驗(yàn) 獲得超7個贊

為了消除掃描結(jié)構(gòu)所需步驟的重復(fù),*sql.Rows您可以引入兩個接口。一個描述*sql.Rows和的已經(jīng)實(shí)現(xiàn)的行為*sql.Row。


// This interface is already implemented by *sql.Rows and *sql.Row.

type Row interface {

    Scan(...interface{}) error

}

另一個抽象出行的實(shí)際掃描步驟。


// have your entity types implement this one

type RowScanner interface {

    ScanRow(Row) error

}

RowScanner 接口的示例實(shí)現(xiàn)如下所示:


type User struct {

    Id       uint

    Username string

    // ...

}


// Implements RowScanner

func (u *User) ScanRow(r Row) error {

    return r.Scan(

        &u.Id,

        &u.Username,

        // ...

    )

}


type UserList struct {

    Items []*User

}


// Implements RowScanner

func (list *UserList) ScanRow(r Row) error {

    u := new(User)

    if err := u.ScanRow(r); err != nil {

        return err

    }

    list.Items = append(list.Items, u)

    return nil

}

使用這些接口,您現(xiàn)在可以為所有通過使用這兩個函數(shù)實(shí)現(xiàn) RowScanner 接口的類型干燥行掃描代碼。


func queryRows(query string, rs RowScanner, params ...interface{}) error {

    rows, err := db.Query(query, params...)

    if err != nil {

        return err

    }

    defer rows.Close()


    for rows.Next() {

        if err := rs.ScanRow(rows); err != nil {

            return err

        }

    }

    return rows.Err()

}


func queryRow(query string, rs RowScanner, params ...interface{}) error {

    return rs.ScanRow(db.QueryRow(query, params...))

}


// example

ulist := new(UserList)

if err := queryRows(queryString, ulist, arg1, arg2); err != nil {

    panic(err)

}


// or

u := new(User)

if err := queryRow(queryString, u, arg1, arg2); err != nil {

    panic(err)

}

如果您有想要掃描的復(fù)合類型,但又想避免重復(fù)枚舉其元素的字段,那么您可以引入一種返回類型字段的方法,并在需要的地方重用該方法。例如:


func (u *User) ScannableFields() []interface{} {

    return []interface{}{

        &u.Id,

        &u.Username,

        // ...

    }

}


func (u *User) ScanRow(r Row) error {

    return r.Scan(u.ScannableFields()...)

}


// your other entity type

type Site struct {

    Id   uint

    Name string

    // ...

}


func (s *Site) ScannableFields() []interface{} {

    return []interface{}{

        &p.Id,

        &p.Name,

        // ...

    }

}


// Implements RowScanner

func (s *Site) ScanRow(r Row) error {

    return r.Scan(s.ScannableFields()...)

}


// your composite

type UserWithSite struct {

    User *User

    Site *Site

}


// Implements RowScanner

func (u *UserWithSite) ScanRow(r Row) error {

    u.User = new(User)

    u.Site = new(Site)

    fields := append(u.User.ScannableFields(), u.Site.ScannableFields()...)

    return r.Scan(fields...)

}


// retrieve from db

u := new(UserWithSite)

if err := queryRow(queryString, u, arg1, arg2); err != nil {

    panic(err)

}



查看完整回答
反對 回復(fù) 2023-05-08
  • 1 回答
  • 0 關(guān)注
  • 107 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學(xué)習(xí)伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號