Есть несколько советов и примечаний 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()
небезопасен для повторного использования.