Daniel Lin
Posted on May 4, 2022
There are some tips and GROM's notes might prevent you debugging in front of laptop all day.
Will not update the zero value
type User struct {
ID int
Age int
}
// if user.Age is 6 in database originally
user.Age = 0
db.Updates(&user)
You will find the age is not updated.
How to solve
db.Model(&user).Select("*").Omit("Role").Update(User{Role: "admin", Age: 0})
db.Model(&user).Update(map[string]interface{}{"role": 0})
What is under the hood?
First, Most of generic in golang rely on reflect package. Gorm use reflect.IsZreo() to check if the field should be updated. source code
Second, 0
is zero value to int type, not zero value to interface{} type, because interface{} underneath is like a pointer to struct which saves object's type and reference. nil
is the zero value for interface{}.
Therefore Gorm can only use Select(fields...)
or map[stirng]interface{}
to explicitly declare fields to be updated.
ErrNotFound
ErrNotFound will not happened in db.Find() function if not record found
WithContext
use WithContext so if the upstream ctx timeout or be cancelled the query can be cancelled too. https://gorm.io/docs/session.html#Context
timeoutCtx, _ := context.WithTimeout(context.Background(), time.Second)
tx := db.WithContext(timeoutCtx)
tx.First(&user) // query with context timeoutCtx
tx.Model(&user).Update("role", "admin") // update with context timeoutCtx
WithContext
is a NewSession
function type in GORM is safe to reuse in same context
https://gorm.io/docs/method_chaining.html#New-Session-Method
Method chaining
Method chaining sometime can make code more readable and more reusable. you can use pointer value to have some optional query parameters.
type Filter struct {
IDs []int
Type *OrderType
UserID *string
}
func (r *Repository) QueryOrders(ctx context.Context, filter Filter) (orders []repository.Order, err error) {
db := r.db.WithContext(ctx)
if filter.UserID != nil {
db = db.Where("user_id = ?", filter.UserID)
}
if len(filter.IDs) > 0 {
db = db.Where("id in (?)", filter.IDs)
}
if filter.Type != nil {
db = db.Where("type = ?", filter.Type)
}
if err := db.Find(&orders).Error; err != nil {
return nil, err
}
}
but be careful Where
is a Chaining Method
in GORM the db returned by Where()
is not safe to reuse.
Posted on May 4, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 27, 2024