Некоторые советы и заметки ГРОМа

Есть несколько советов и примечаний GROM, которые могут помешать вам отлаживать программу перед ноутбуком весь день.

Не обновлять нулевое значение

type User struct {
  ID int
  Age int
}
// if user.Age is 6 in database originally 
user.Age = 0
db.Updates(&user)
Войдите в полноэкранный режим Выйдите из полноэкранного режима

Вы обнаружите, что возраст не обновляется.

Как решить

db.Model(&user).Select("*").Omit("Role").Update(User{Role: "admin", Age: 0})
db.Model(&user).Update(map[string]interface{}{"role": 0})
Войдите в полноэкранный режим Выйти из полноэкранного режима

Что находится под капотом?

Во-первых, большинство generic в golang полагаются на пакет reflect. Gorm использует reflect.IsZreo() для проверки необходимости обновления поля. исходный код
Во-вторых, 0 — это нулевое значение для типа int, а не нулевое значение для типа interface{}, потому что interface{} под ним — это как указатель на struct, который сохраняет тип и ссылку объекта. nil — это нулевое значение для interface{}.

Поэтому Gorm может использовать только Select(fields...) или map[stirng]interface{} для явного объявления обновляемых полей.

ErrNotFound

ErrNotFound не произойдет в функции db.Find(), если запись не найдена.

WithContext

Используйте WithContext, чтобы в случае таймаута или отмены восходящего ctx запрос тоже мог быть отменен. 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 является типом функции NewSession в GORM безопасно использовать повторно в том же контексте
https://gorm.io/docs/method_chaining.html#New-Session-Method

Цепочка методов

Цепочка методов иногда может сделать код более читабельным и более многоразовым. Вы можете использовать значение указателя, чтобы иметь некоторые необязательные параметры запроса.

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
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима

но будьте осторожны Where является Chaining Method в GORM, db, возвращаемый Where() небезопасен для повторного использования.

Оцените статью
Procodings.ru
Добавить комментарий