Keep應用和數據庫代碼獨立。
// 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()
如果你不介意使用它們,指針的零值爲零 - 'type Role {Code * string}' – codepushr