默认约定
- gorm使用名为ID的字段作为主键
- 使用结构体的蛇形复数作为表名 这种情况自定义了表名
type Product struct {
Code string
Price uint
}
func (p Product) TableName() string {
return "product"
}
- 字段名的蛇形作为列名
- 使用CreatedAt、UpdatedAt字段作为创建、更新时间
查询
First/Last
使用First时,查询不到数据会返回ErrRecordNotFound。First and Last 方法会按主键排序找到第一条记录和最后一条记录
result := db.First(&product)
fmt.Println("the number of result: ", result.RowsAffected)
fmt.Println("use first to serch, the error is : ", result.Error)
Find查询多条数据
查询不到不会返回错误
products := make([]*Product, 2)
result := db.Where("code = ?", "D42").Find(&products)
fmt.Println(result.RowsAffected)
fmt.Println(result.Error)
db.Where("code IN ?", []string{"D42", "F42"}).Find(&products)
db.Where("code = ? OR code = ?", "D42", "F42").Find(&products)
使用结构体查询只会查询非零字段
db.Where(&Product{"F42", 0}).Find(&products)
上面这段查询只是查找code = F42的结果,并没有price = 0
如果要查询零值字段,使用map来构建查询条件
db.Where(map[string]interface{}{"Code": "F42", "Price": 0}).Find(&products)
更新
如果你执行一个没有任何条件的批量更新,GORM 默认不会运行,并且会返回 ErrMissingWhereClause 错误
Model指定表名
db.Model(&Product{}).Where("code = ?", "F426").Update("code", "FF")
当时用Updates的参数为struct的时候可以将Model省略
db.Where("code = ?", "D42").Updates(&Product{Code: "D42", Price: 188})
如果更新零值使用map或select字段
db.Model(&Product{}).Where("code = ?", "F42").Updates(map[string]interface{}{"price": 0})
db.Model(&Product{}).Where("code = ?", "D42").Select("code").Update("code", "")
更新选定字段
db.Model(&Product{}).Where("code = ?", "D42").Select("code").Updates(&Product{Code: "D41", Price: 188})
price并不会修改
表达式更新
db.Model(&Product{}).Where("price != ?", 0).Update("price", gorm.Expr("price * ? + ?", 2, 100))
删除
物理删除
db.Where("price = ?", 0).Delete(&Product{})
软删除
如果包含了gorm.DeletedAt(也在gorm.Model中),那么该模型将会自动获得软删除能力
当调用Delete时,GORM并不会从数据库中删除该记录,而是将该记录的DeleteAt设置为当前时间,而后的一般查询方法将无法查找到此条记录。
查找被软删除的记录
使用Unscoped来查询被软删除的记录
db.Unscoped().Where("age = ?", 0).Find(&users)
永久删除
db.Unscoped().Where("age = ?", 0).Delete(&User{})
事务
gorm提供了Begin``Commit``Rollback方法用于使用事务
func main() {
db, err := gorm.Open(
mysql.Open("root:123456@tcp(127.0.0.1:3306)/gorm?charset=utf8mb4&parseTime=True&loc=Local"),
&gorm.Config{})
if err != nil {
panic("failed to connect database")
}
tx := db.Begin()
if err = tx.Create(&User{Name: "name"}).Error; err != nil {
// when meet error to rollback
tx.Rollback()
return
}
if err = tx.Create(&User{Name: "name1"}).Error; err != nil {
tx.Rollback()
return
}
tx.Commit()
}
Transaction
Gorm提供了Transction方法用于自动提交事务,避免用户漏写Commit、Rollback
func main() {
db, err := gorm.Open(
mysql.Open("root:123456@tcp(127.0.0.1:3306)/gorm?charset=utf8mb4&parseTime=True&loc=Local"),
&gorm.Config{})
if err != nil {
panic("failed to connect database")
}
if err = db.Transaction(func(tx *gorm.DB) error {
if err = tx.Create(&User{Name: "name"}).Error; err != nil {
return err
}
if err = tx.Create(&User{Name: "name1"}).Error; err != nil {
return err
}
return nil
}); err != nil {
return
}
}
禁用默认事务
gorm.Config中SkipDefaultTransaction设为true
Hook
Hook是在创建、查询、更新、删除等操作之前、之后自动调用的函数
如果任何Hook返回错误,gorm将停止后续的操作并回滚事务
创建
- BeforeSave
- BeforeCreate
- AfterCreate
- AfterSave
func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
if u.Age < 0 {
return errors.New("can't save invalid age")
}
return nil
}
type Email struct {
ID int64
Email string
}
func (u *User) AfterCreate(tx *gorm.DB) (err error) {
return tx.Create(&Email{ID: u.ID, Email: u.Name + "@xxx.com"}).Error
}
更新
- BeforeSave
- AfterSave
- BeforeUpdate
- AfterUpdate
删除
- BeforeDelete
- AfterDelete