English
Deeply Understanding the Controllability of Pointer-Type Fields in GORM
Introduction
When using GORM for database operations, we often encounter scenarios where precise control over field updates is required. Especially for fields of boolean and string types, how can we ensure that we can correctly update field values to zero values (such as false or empty string) is a common issue. This article will explore in depth the use of pointer-type fields in GORM and how to correctly implement controllable updates of field values.
Boolean type field issue
Limitations of non-pointer boolean types
go
type Task struct {
Id uint
IsCompleted bool `gorm:"type:tinyint(1)"`
}When using the above structure, if we want to IsCompleted from true Updated to false, will encounter problems:
go
db.Model(&Task{Id: 1}).Updates(Task{IsCompleted: false})
// Actually, no updates will be executed at all!This is because GORM ignores zero-value fields by default (false is the zero value of the boolean type), considering that these fields do not need to be updated.
Solution: Use a Boolean pointer
go
type Task struct {
Id uint
IsCompleted *bool `gorm:"type:tinyint(1)"`
}Now we can update it like this:
go
completed := false
db.Model(&Task{Id: 1}).Updates(Task{IsCompleted: &completed})
// Successfully updated IsCompleted to falseBy using pointers, we can clearly distinguish between "not updating this field" and "setting this field to the zero value".
Special cases of string-type fields
The problem with string pointers
go
type Task struct {
Id int64 `gorm:"culumn:id;bigint;not null;primary_key;comment:Record Id;"`
State uint8 `gorm:"culumn:state;tinyint(1);not null;default:1;"`
FailedReason *string `gorm:"culumn:failed_reason;size:128;null;"`
}When we try to update the string pointer field:
go
db.Model(&Task{Id: 1}).Updates(Task{FailedReason: nil})
// May not update in some GORM versions!Reminder
If the task with task.id 1 fails and the failure reason is updated, if at some point you want to update the value of this field again through the above GORM Updates operation, the operation will not update the in the Task data table failed_reason is NULL!
Solution: use a specific update method UpdateColumn
go
db.Model(&Task{Id: 1}).UpdateColumn("failed_reason", nil)Reminder
Updating via the UpdateColumn method can bypass these zero-value restrictions!
A Deep Understanding of GORM's Update Mechanism
GORM's update behavior follows these rules:
For non-pointer type fields:
Zero values will be ignored (not updated)
Non-zero values will be updated.
For pointer type fields:
nil pointers are ignored (not updated)
Non-nil pointers will be updated even if they point to a zero value.
Exceptions:
Some types (such as string pointers) may have special handling in some GORM versions.
Using specific methods (such as
UpdateColumn) can bypass these restrictions
best practices
For fields that require precise control of zero values, use pointer types.
Boolean value:
*boolString:
*stringNumber:
*int,*float64waitClarify the update intent
Use
SelectSpecify the fields to updateFor critical updates, consider using
UpdateColumnMaintain consistency
Use pointer or non-pointer types consistently throughout the project.
Explicitly agree on an update strategy within the team.
Test verification
Write test cases for the scenario of updating a zero value.
Verify behavior across different GORM versions
Summary
By reasonably using pointer types and correct update methods, we can fully control field update behavior in GORM. The key lies in understanding:
Pointer types allow us to distinguish between “no update” and “update to zero value”.
Some field types may require special handling.
Choosing the correct update method has a decisive impact on the results.
After mastering these techniques, you will be able to control database operations more precisely and avoid unexpected behavior caused by zero-value issues.