go 自定义error怎么判断是否相等_Go Web 小技巧(二)GORM 使用自定义类型
不知道大家在使用 Gorm 的時候,是否有遇到過復雜類型 ( map, struct...) 如何映射到數據庫的字段上的問題?
本文分別介紹通過實現通用接口和 Hook 的方式綁定復雜的數據類型。
一、GORM 模型定義
type User struct {gorm.ModelName stringAge sql.NullInt64Birthday *time.TimeEmail string `gorm:"type:varchar(100);unique_index"`Role string `gorm:"size:255"` // 設置字段大小為255MemberNumber *string `gorm:"unique;not null"` // 設置會員號(member number)唯一并且不為空Num int `gorm:"AUTO_INCREMENT"` // 設置 num 為自增類型Address string `gorm:"index:addr"` // 給address字段創建名為addr的索引IgnoreMe int `gorm:"-"` // 忽略本字段 }這是 GORM 官方文檔當中模型定義的一個例子,但是我們在實際使用過程當中往往會遇到需要復雜類型例如 map 或者是一些自定義的類型進行綁定。
我們在文檔的描述當中可以看到這么一段話:
模型(Models)通常只是正常的 golang structs、基本的 go 類型或它們的指針。 同時也支持sql.Scanner及driver.Valuer 接口(interfaces)。自已的數據類型只需要實現這兩個接口就可以實現數據綁定了,文檔只有一句話我們看看具體怎么做。
二、通過實現 sql.Scanner,driver.Valuer 接口實現數據綁定
2.1 接口文檔
// sql.Scanner type Scanner interface {// Scan assigns a value from a database driver.//// The src value will be of one of the following types://// int64// float64// bool// []byte// string// time.Time// nil - for NULL values//// An error should be returned if the value cannot be stored// without loss of information.//// Reference types such as []byte are only valid until the next call to Scan// and should not be retained. Their underlying memory is owned by the driver.// If retention is necessary, copy their values before the next call to Scan.Scan(src interface{}) error }// driver.Valuer type Valuer interface {// Value returns a driver Value.// Value must not panic.Value() (Value, error) }我們可以發現 Valuer 用于保存數據的時候,Scaner 用于數據從數據庫映射到 model 的時候
2.2 實現接口
下面我們來一個實際的例子
// Args 參數 type Args map[string]string// Scan Scanner func (args Args) Scan(value interface{}) error {if value == nil {return nil}b, ok := value.([]byte)if !ok {return fmt.Errorf("value is not []byte, value: %v", value)}return json.Unmarshal(b, &args) }// Value Valuer func (args Args) Value() (driver.Value, error) {if args == nil {return nil, nil}return json.Marshal(args) }在使用的時候我們只要再加上一個數據類型就 OK 了
type Data struct {Args Args `json:"args" gorm:"type:text"` }2.3 抽象通用工具函數
在實際的使用中我們可能會有許多的類型的需要這樣存儲,所以我們直接抽象一個公用的工具函數
// scan for scanner helper func scan(data interface{}, value interface{}) error {if value == nil {return nil}switch value.(type) {case []byte:return json.Unmarshal(value.([]byte), data)case string:return json.Unmarshal([]byte(value.(string)), data)default:return fmt.Errorf("val type is valid, is %+v", value)} }// for valuer helper func value(data interface{}) (interface{}, error) {vi := reflect.ValueOf(data)// 判斷是否為 0 值if vi.IsZero() {return nil, nil}return json.Marshal(data) }使用的時候只需要調用一下
// Args 參數 type Args map[string]string// Scan Scanner func (args Args) Scan(value interface{}) error {return scan(&args, value) }// Value Valuer func (args Args) Value() (driver.Value, error) {return value(args) }三、通過 hook 實現數據綁定
除了上面的這種方法有沒有其他的實現方式呢?
當然是有的,從上面的例子我們可以發現,實現方式就是保存數據的時候將數據轉換為基本類型,然后在取出來綁定數據的時候再轉換一下,這個過程我們也可以通過 GORM 的 Hook 實現。利用 BeforeSave 在數據保存前轉換,再利用 AfterFind 在數據取出來之后轉換即可。但是這種方式我們需要在 struct 中定義一個用于實際映射數據庫數據的字段。
// Data Data type Data struct {Args map[string]interface{} `json:"args" gorm:"-"`ArgsStr string `json:"-" gorm:"column:args"` }// BeforeSave 數據保存前 func (data *Data) BeforeSave() error {if data.Args == nil {return nil}b, err := json.Marshal(&data.Args)if err != nil {return err}data.ArgsStr = string(b)return nil }// AfterFind 查詢之后 func (data *Data) AfterFind() error {if data.ArgsStr == "" {return nil}return json.Unmarshal([]byte(data.ArgsStr), &data.Args) }這樣同樣可以達到相似的效果
總結
這篇文章介紹了兩種通用數據類型在 GORM 中的綁定方式:
- 通過實現相關的接口實現,并且抽象了一個通用的輔助函數
- 通過 hook 實現
一般推薦使用第一種方法,只是需要單獨定義數據類型,第二種方法需要多一個輔助字段,這種方式如果相關的字段過多會很不優雅。
感謝閱讀,這是 Go Web 小技巧系列的第二篇文章,下一篇為大家介紹參數綁定當中的一些小技巧
博客原文
Go Web 小技巧(二)GORM 使用自定義類型?lailin.xyz總結
以上是生活随笔為你收集整理的go 自定义error怎么判断是否相等_Go Web 小技巧(二)GORM 使用自定义类型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vuex 编译项目_俺咋能看懂公司前端项
- 下一篇: dve 二维数组信号 显示波形_函数任意