2014-01-16 8 views
8

Wenn man mit einer Datenbank arbeitet, ist ein Null* Typ für die meisten Szenarien nützlich, da man normalerweise keinen "Null" -Wert durchläuft, sondern die NOT NULL-Bedingungen usw. und Sie daran erinnern, dass Sie nicht alle notwendigen Daten weitergegeben haben.golang funktioniert effektiv mit Null * Typen

So erstellen Sie eine Struktur wie folgt aus:

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

Das ist großartig, aber jetzt können Sie keinen direkten Zugriff auf die Eigenschaften erhalten und Role.Id.Value sowohl bekommen und stellen Sie verwenden müssen, das ist ziemlich erhalten wird Alt in einer großen App, wenn Sie den zusätzlichen Schritt jedes Mal haben müssen, wenn Sie auf die Eigenschaften zugreifen möchten.

Es wäre schön, wenn Sie direkt zB zuweisen könnten. Role.Code = "Fsfs", und in der Lage sein, etwas wie Role.Code.IsNull zu tun, wenn Sie an Null-Überprüfung interessiert sind. Ist so etwas möglich?

+0

Pointers haben Null als Nullwert, wenn Sie nicht mit ihnen zu arbeiten nichts dagegen - 'Typ Rollen struct {Code * string}' – codepushr

Antwort

1

Verwenden Sie Zwischenzeigerwert (e) eine Option?

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

Sie können Role.Code so Zugang:

var r *Role 
r.Code = *code 

Sie für null wie folgt überprüfen:

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

Wenn Sie den Wert von r ändern .Code manuell ohne Verwendung eines sql.Scanners könnte ein Setter hilfreich sein:

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

Ich habe versucht, das hier aus: https://play.golang.org/p/faxQUm-2lr

1

Halten App und Datenbank-Code separaten.

// Role belongs to app code, no compromises. 

type Role struct { 
    Id int64 
    Code string 
} 

Modellieren Sie die Datenbank.

// Database has tables with columns. 

type Table struct { 
    Name string 
    Columns []string 
} 

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

Einmal Code zum Konvertieren zwischen Modell- und Datenbankzeile schreiben.

// 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, 
    } 
} 

Ihr Schema ist vom App-Modell entkoppelt. Sie können Strukturen wie Benutzerkontaktdetails beim Speichern oder Laden abflachen.

// 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", 
    }, 
} 

Es ist flexibel. Sie können sogar Join-Zeilen ohne Zwischenstrukturen scannen.

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