golang有效地处理Null*类型
如果使用数据库,则golang有效地处理Null*类型,go,Go,如果使用数据库,则Null*类型对于大多数情况都很有用,因为通常不希望出现“零”值,希望非Null约束等启动并提醒您尚未传递所有必要的数据 因此,您可以创建如下结构: type Role struct { Id sql.NullInt64 Code sql.NullString } 这很好,但现在您无法直接访问属性,必须使用Role.Id.Value来获取和设置属性,在大型应用程序中,这将变得非常陈旧,因为每次您需要访问属性时都需要额外的步骤 如果您可以直接分配,例如,Ro
Null*
类型对于大多数情况都很有用,因为通常不希望出现“零”值,希望非Null约束等启动并提醒您尚未传递所有必要的数据
因此,您可以创建如下结构:
type Role struct {
Id sql.NullInt64
Code sql.NullString
}
这很好,但现在您无法直接访问属性,必须使用Role.Id.Value
来获取和设置属性,在大型应用程序中,这将变得非常陈旧,因为每次您需要访问属性时都需要额外的步骤
如果您可以直接分配,例如,
Role.code=“Fsfs”
,并且当您对空检查感兴趣时,能够执行类似于Role.code.IsNull的操作,那就太好了。这样做可能吗?是否使用中间指针值作为选项
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)
}
您可以访问角色。代码如下:
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)
}
我在这里尝试过:将应用程序和数据库代码分开
对数据库进行建模
// 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()
如果您不介意使用指针,指针的零值为nil-type Role struct{code*string}
Hi-lee。。。我不喜欢将模型对象定义(角色)与底层数据库定义(sql.Null*)混合使用……如果您愿意,我可以演示如何处理它。。。。
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()