我正在使用 gorm.io 库,版本 1.20.8,目前可用的最后一个。 我有这个简化的模型:
type ExternalUser struct {
BaseModel
Name string `gorm:"type:char(255);uniqueIndex:compositeIndex;not null"`
Password string
HashPassword string
}
使用这个 BeforeUpdate 函数
func (user *ExternalUser) BeforeUpdate(tx *gorm.DB) error {
pass, _ := utils.HashPassword(user.Password)
tx.Statement.SetColumn("HashPassword", pass)
encryptedPass := utils.EncryptString(user.Password)
tx.Statement.SetColumn("Password", encryptedPass)
return nil
}
但它似乎从未被调用过,我不明白为什么。 这是我调用的更新函数:
func UpdateExternalUser(dataForm command.ExternalUserUpdate, externalUserID string, userId uuid.UUID) (int64, error) {
dataForm.UpdatedUserID = userId
result := database.DB().Table("external_user").Where("id=?", externalUserID).Updates(&dataForm)
if err := result.Error; err != nil {
return -1, err
}
row := result.RowsAffected
return row, nil
}
BeforeCreate 钩子工作正常。
上面模型中的 BaseModel 类型定义如下:
type BaseModel struct {
ID uuid.UUID `gorm:"type:char(36);primary_key;"`
Version int64 `gorm:"not null;"`
CreatedAt time.Time `gorm:"index;"`
UpdatedAt time.Time `gorm:"index;"`
CreatedUserID uuid.UUID `gorm:"type:char(36);index;not null;"`
UpdatedUserID uuid.UUID `gorm:"type:char(36);index;not null;"`
}
func (BaseModel *BaseModel) BeforeCreate(tx *gorm.DB) error {
newUUID := uuid.NewV4()
tx.Statement.SetColumn("ID", newUUID)
tx.Statement.SetColumn("Version", 0)
return nil
}
更新
作为评论指出,我将查询更改如下:
result := database.DB().Model(&model.ExternalUser{}).Where("id=?", externalUserID).Updates(&dataForm)
现在确实发生了钩子,但是我遇到了一个恐慌错误,我想是因为我传递的模型结构 Model(&model.ExternalUser{}) 是空的。
这里是传递的错误信息:
2020/12/18 20:31:32 [Recovery] 2020/12/18 - 20:31:32 panic recovered:
PUT /core/api/v1/external-user/4dd6223f-0546-4e20-a6e1-9cd89499b281 HTTP/1.1
Host: localhost:8090
Accept: */*
Accept-Encoding: gzip, deflate, br
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 407
Content-Type: application/json
Postman-Token: 9844ea91-5e25-4123-a950-0a19f80352a1
Uber-Trace-Id: 77b3baa8890e5788:7ada969a1b89b7e5:77b3baa8890e5788:1
User-Agent: PostmanRuntime/7.26.8
reflect: call of reflect.Value.Field on string Value
/usr/local/go/src/reflect/value.go:850 (0x411ac04)
Value.Field: panic(&ValueError{"reflect.Value.Field", v.kind()})
/Users/xxxx/Project/go/pkg/mod/gorm.io/gorm@v1.20.8/schema/field.go:393 (0x4a41a93)
(*Field).setupValuerAndSetter.func2: fieldValue := reflect.Indirect(value).Field(field.StructField.Index[0]).Field(field.StructField.Index[1])
/Users/xxxx/Project/go/pkg/mod/gorm.io/gorm@v1.20.8/callbacks/update.go:230 (0x4ae6f74)
ConvertToAssignments: value, isZero := field.ValueOf(updatingValue)
/Users/xxxx/Project/go/pkg/mod/gorm.io/driver/mysql@v1.0.3/update_with_order_by_limit.go:20 (0x4aeeef2)
Update: if set := callbacks.ConvertToAssignments(db.Statement); len(set) != 0 {
/Users/xxxx/Project/go/pkg/mod/gorm.io/gorm@v1.20.8/callbacks.go:105 (0x4a56f33)
(*processor).Execute: f(db)
/Users/xxxx/Project/go/pkg/mod/gorm.io/gorm@v1.20.8/finisher_api.go:318 (0x4a61a27)
(*DB).Updates: tx.callbacks.Update().Execute(tx)
更新/2
经过一些测试后,我发现使用这条线一切正常:
result := database.DB().Model(&model.ExternalUser{}).Where("id = ?", externalUserID).Updates(model.ExternalUser{Name: dataForm.Name, Password: dataForm.Password})
但在这种情况下,我被迫在更新条款中指定每个字段,而不是只传递结构。