golang与Null *类型一起有效地工作

时间:2014-01-16 01:38:35

标签: go

如果正在使用数据库,Null*类型对大多数情况都很有用,因为通常不希望“零”值通过,您希望NOT NULL约束等启动和提醒你没有传递所有必要的数据。

所以你创建了如下结构:

type Role struct {
    Id   sql.NullInt64
    Code sql.NullString
}

太棒了,但现在你无法直接访问这些属性并且必须使用Role.Id.Value来获取和设置,当你需要额外的步骤时,这将在大型应用程序中变得相当旧每次您想要访问这些属性。

如果你可以直接分配,那将是很好的。 Role.Code = "Fsfs",当您对空检查感兴趣时,可以执行Role.Code.IsNull之类的操作。这样的事情有可能吗?

3 个答案:

答案 0 :(得分:1)

使用中间指针值是一个选项吗?

package main

import "fmt"

type tmp struct {
    Value int
}

func getInt() *int {
    i := 123

    return &i
}

func main() {
    // Re
    var v *int

    v = nil

    fmt.Printf("%T / %v\n", v, v)

    if v == nil {
        println("nil...")
    }

    v = getInt()

    fmt.Printf("%T / %v\n", v, *v)

    if v != nil {
        println("not nil...")
    }

    s := tmp{*v}

    fmt.Printf("%T / %v\n", s, s)
}

http://play.golang.org/p/lBrwTKh6-v

答案 1 :(得分:1)

您可以像这样访问Role.Code:

var r *Role
r.Code = *code

您可以像这样检查null:

fmt.Println(r.Code, r.Code.Valid)

如果在不使用sql.Scanner的情况下手动更改r.Code的值,则Setter可能会有所帮助:

func (r *Role) SetCode(code string) {
  r.Code.String = code
  r.Code.Valid = true
}
func main() {
var r *Role 
r.SetCode("mi")
if r.Code.Valid {
  fmt.Println(r.Code)
}

我在这里尝试了这个:https://play.golang.org/p/faxQUm-2lr

答案 2 :(得分:1)

将应用和数据库代码分开

// Role belongs to app code, no compromises.

type Role struct {
    Id int64
    Code string
}

为数据库建模。

// Database has tables with columns.  

type Table struct {
    Name string
    Columns []string
}

var RoleTable = Table{
    Name: "roles",
    Columns: []string{
        "id",
        "code",
    },
}

编写一次代码以在模型和数据库行之间进行转换。

// Database package needs to make it work.

// Write a model to database row. 
type Writer struct {
    Role
}

func (w *Writer) Write() []interface{} {
    return []interface{}{
        w.Role.Id,
        sql.NullString{
            Valid: len(w.Role.Code) > 0,
            String: w.Role.String,
        },
    }
}

// Read a database row into model. 
type Reader struct {
    Id int64
    Code sql.NullString
}

func (r *Reader) Scan(row *sql.Row) error {
    return row.Scan(
        &r.Id,
        &r.Code,
    )
}

func (r *Reader) Read() Role {
    return Role{
        Id: r.Id,
        Code: r.Code.String,
    }
}

您的架构与应用模型分离。保存或加载时,您可以压缩用户联系人详细信息等结构。

// Nested struct in app code. 
type User struct {
    TwitterProfile struct {
        Id string
        ScreenName string
    }
}

// Database row is normalized flat. 
var UserTable = Table{
    Name: "users",
    Columns: []string{
        "twitter_id",
        "twitter_screen_name",
    },
}

它很灵活。您甚至可以扫描没有中间结构的连接行。

type RowMux struct {
    vs []interface{}
}

func (mux *RowMux) Scan(vs ...interface{}) error {
    mux.vs = append(mux.vs, vs...)
    return nil
}

func (mux *RowMux) Mux(row *sql.Row) error {
    return row.Scan(mux.vs...)
}

// Scan join rows!
row := db.QueryRow(`
    SELECT users.*, roles.*
    FROM users
    JOIN roles ON users.id = roles.user_id
    WHERE users.twitter_id = "123"
`)
mux := &RowMux{}
userReader := &UserReader{}
userReader.Scan(mux)
roleReader := &RoleReader{}
roleReader.Scan(mux)
if err := mux.Mux(row); err != nil {
    panic(err)
}
user := userReader.Read()
role := roleReader.Read()