DEV Community

Daniel Lin
Daniel Lin

Posted on


Some GORM Tips and Notes

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
Enter fullscreen mode Exit fullscreen mode

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})
Enter fullscreen mode Exit fullscreen mode

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 will not happened in db.Find() function if not record found


use WithContext so if the upstream ctx timeout or be cancelled the query can be cancelled too.

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
Enter fullscreen mode Exit fullscreen mode

WithContext is a NewSession function type in GORM is safe to reuse in same context

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
Enter fullscreen mode Exit fullscreen mode

but be careful Where is a Chaining Method in GORM the db returned by Where() is not safe to reuse.

Top comments (0)

12 APIs That You Will Love

>> Check out this classic DEV post <<