智能选择字段
GORM 允许使用 Select 选择特定字段,如果您经常在应用程序中使用它,也许您想定义一个较小的结构供 API 使用,它可以自动选择特定字段,例如:
type User struct { ID uint Name string Age int Gender string // hundreds of fields } type APIUser struct { ID uint Name string } // Select `id`, `name` automatically when querying db.Model(&User{}).Limit(10).Find(&APIUser{}) // SELECT `id`, `name` FROM `users` LIMIT 10 |
注意 QueryFields 模式将根据当前模型的所有字段名称进行选择
db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{ QueryFields: true, }) db.Find(&user) // SELECT `users`.`name`, `users`.`age`, ... FROM `users` // with this option // Session Mode db.Session(&gorm.Session{QueryFields: true}).Find(&user) // SELECT `users`.`name`, `users`.`age`, ... FROM `users` |
锁定(用于更新)
GORM 支持不同类型的锁,例如:
db.Clauses(clause.Locking{Strength: "UPDATE"}).Find(&users) // SELECT * FROM `users` FOR UPDATE db.Clauses(clause.Locking{ Strength: "SHARE", Table: clause.Table{Name: clause.CurrentTable}, }).Find(&users) // SELECT * FROM `users` FOR SHARE OF `users` db.Clauses(clause.Locking{ Strength: "UPDATE", Options: "NOWAIT", }).Find(&users) // SELECT * FROM `users` FOR UPDATE NOWAIT |
有关更多详细信息,请参阅原始 SQL 和 SQL 构建器
子查询
子查询可以嵌套在查询中,GORM 可以在使用 *gorm.DB 对象作为参数时生成子查询
db.Where("amount > (?)", db.Table("orders").Select("AVG(amount)")).Find(&orders) // SELECT * FROM "orders" WHERE amount > (SELECT AVG(amount) FROM "orders"); subQuery := db.Select("AVG(age)").Where("name LIKE ?", "name%").Table("users") db.Select("AVG(age) as avgage").Group("name").Having("AVG(age) > (?)", subQuery).Find(&results) // SELECT AVG(age) as avgage FROM `users` GROUP BY `name` HAVING AVG(age) > (SELECT AVG(age) FROM `users` WHERE name LIKE "name%") |
从子查询
GORM 允许您使用 Table 方法在 FROM 子句中使用子查询,例如:
db.Table("(?) as u", db.Model(&User{}).Select("name", "age")).Where("age = ?", 18).Find(&User{}) // SELECT * FROM (SELECT `name`,`age` FROM `users`) as u WHERE `age` = 18 subQuery1 := db.Model(&User{}).Select("name") subQuery2 := db.Model(&Pet{}).Select("name") db.Table("(?) as u, (?) as p", subQuery1, subQuery2).Find(&User{}) // SELECT * FROM (SELECT `name` FROM `users`) as u, (SELECT `name` FROM `pets`) as p |
分组条件
使用组条件更容易编写复杂的 SQL 查询
db.Where( db.Where("pizza = ?", "pepperoni").Where(db.Where("size = ?", "small").Or("size = ?", "medium")), ).Or( db.Where("pizza = ?", "hawaiian").Where("size = ?", "xlarge"), ).Find(&Pizza{}).Statement // SELECT * FROM `pizzas` WHERE (pizza = "pepperoni" AND (size = "small" OR size = "medium")) OR (pizza = "hawaiian" AND size = "xlarge") |
IN 多列
选择多列的 IN
db.Where("(name, age, role) IN ?", [][]interface{}{{"jinzhu", 18, "admin"}, {"jinzhu2", 19, "user"}}).Find(&users) // SELECT * FROM users WHERE (name, age, role) IN (("jinzhu", 18, "admin"), ("jinzhu 2", 19, "user"));
命名参数
GORM 支持使用 sql.NamedArg 或 map[string]interface{}{} 命名参数,例如:
db.Where("name1 = @name OR name2 = @name", sql.Named("name", "jinzhu")).Find(&user)
// SELECT * FROM `users` WHERE name1 = "jinzhu" OR name2 = "jinzhu"
db.Where("name1 = @name OR name2 = @name", map[string]interface{}{"name": "jinzhu"}).First(&user)
// SELECT * FROM `users` WHERE name1 = "jinzhu" OR name2 = "jinzhu" ORDER BY `users`.`id` LIMIT 1
查看 Raw SQL 和 SQL Builder 了解更多详情
Find To Map
GORM允许扫描结果映射到map[string]interface{}或者[]map[string]interface{},不要忘记指定Model或者Table,例如:
result := map[string]interface{}{} db.Model(&User{}).First(&result, "id = ?", 1) var results []map[string]interface{} db.Table("users").Find(&results) |
第一或初始化
获取第一个匹配记录或使用给定条件初始化新实例(仅适用于结构或映射条件)
// User not found, initialize it with give conditions db.FirstOrInit(&user, User{Name: "non_existing"}) // user -> User{Name: "non_existing"} // Found user with `name` = `jinzhu` db.Where(User{Name: "jinzhu"}).FirstOrInit(&user) // user -> User{ID: 111, Name: "Jinzhu", Age: 18} // Found user with `name` = `jinzhu` db.FirstOrInit(&user, map[string]interface{}{"name": "jinzhu"}) // user -> User{ID: 111, Name: "Jinzhu", Age: 18} |
如果未找到记录,则使用更多属性初始化结构,这些属性将不会用于构建 SQL 查询
// User not found, initialize it with give conditions and Attrs db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrInit(&user) // SELECT * FROM USERS WHERE name = 'non_existing' ORDER BY id LIMIT 1; // user -> User{Name: "non_existing", Age: 20} // User not found, initialize it with give conditions and Attrs db.Where(User{Name: "non_existing"}).Attrs("age", 20).FirstOrInit(&user) // SELECT * FROM USERS WHERE name = 'non_existing' ORDER BY id LIMIT 1; // user -> User{Name: "non_existing", Age: 20} // Found user with `name` = `jinzhu`, attributes will be ignored db.Where(User{Name: "Jinzhu"}).Attrs(User{Age: 20}).FirstOrInit(&user) // SELECT * FROM USERS WHERE name = jinzhu' ORDER BY id LIMIT 1; // user -> User{ID: 111, Name: "Jinzhu", Age: 18} |
无论是否找到,都为struct分配属性,这些属性不会用于构建SQL查询,最终数据也不会保存到数据库中
// User not found, initialize it with give conditions and Assign attributes db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrInit(&user) // user -> User{Name: "non_existing", Age: 20} // Found user with `name` = `jinzhu`, update it with Assign attributes db.Where(User{Name: "Jinzhu"}).Assign(User{Age: 20}).FirstOrInit(&user) // SELECT * FROM USERS WHERE name = jinzhu' ORDER BY id LIMIT 1; // user -> User{ID: 111, Name: "Jinzhu", Age: 20}
首先或创建(FirstOrCreate)
获取第一个匹配记录或在给定条件下创建一个新记录(仅适用于结构、映射条件),RowsAffected 返回创建/更新记录的计数
// User not found, create a new record with give conditions result := db.FirstOrCreate(&user, User{Name: "non_existing"}) // INSERT INTO "users" (name) VALUES ("non_existing"); // user -> User{ID: 112, Name: "non_existing"} // result.RowsAffected // => 1 // Found user with `name` = `jinzhu` result := db.Where(User{Name: "jinzhu"}).FirstOrCreate(&user) // user -> User{ID: 111, Name: "jinzhu", "Age": 18} // result.RowsAffected // => 0 |
如果没有找到记录,则创建具有更多属性的结构,这些 Attrs 将不会用于构建 SQL 查询
// User not found, create it with give conditions and Attrs db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrCreate(&user) // SELECT * FROM users WHERE name = 'non_existing' ORDER BY id LIMIT 1; // INSERT INTO "users" (name, age) VALUES ("non_existing", 20); // user -> User{ID: 112, Name: "non_existing", Age: 20} // Found user with `name` = `jinzhu`, attributes will be ignored db.Where(User{Name: "jinzhu"}).Attrs(User{Age: 20}).FirstOrCreate(&user) // SELECT * FROM users WHERE name = 'jinzhu' ORDER BY id LIMIT 1; // user -> User{ID: 111, Name: "jinzhu", Age: 18} |
无论是否找到记录,都将属性分配给记录,并将它们保存回数据库。
// User not found, initialize it with give conditions and Assign attributes db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrCreate(&user) // SELECT * FROM users WHERE name = 'non_existing' ORDER BY id LIMIT 1; // INSERT INTO "users" (name, age) VALUES ("non_existing", 20); // user -> User{ID: 112, Name: "non_existing", Age: 20} // Found user with `name` = `jinzhu`, update it with Assign attributes db.Where(User{Name: "jinzhu"}).Assign(User{Age: 20}).FirstOrCreate(&user) // SELECT * FROM users WHERE name = 'jinzhu' ORDER BY id LIMIT 1; // UPDATE users SET age=20 WHERE id = 111; // user -> User{ID: 111, Name: "jinzhu", Age: 20} |
优化器/索引提示
优化器提示允许控制查询优化器选择某个查询执行计划,GORM 通过 gorm.io/hints 支持它,例如:
import "gorm.io/hints" db.Clauses(hints.New("MAX_EXECUTION_TIME(10000)")).Find(&User{}) // SELECT * /*+ MAX_EXECUTION_TIME(10000) */ FROM `users`
索引提示允许将索引提示传递给数据库,以防查询计划器感到困惑。
import "gorm.io/hints" db.Clauses(hints.UseIndex("idx_user_name")).Find(&User{}) // SELECT * FROM `users` USE INDEX (`idx_user_name`) db.Clauses(hints.ForceIndex("idx_user_name", "idx_user_id").ForJoin()).Find(&User{}) // SELECT * FROM `users` FORCE INDEX FOR JOIN (`idx_user_name`,`idx_user_id`)" |
有关更多详细信息,请参阅优化器提示/索引/评论
迭代
GORM 支持遍历 Rows
rows, err := db.Model(&User{}).Where("name = ?", "jinzhu").Rows() defer rows.Close() for rows.Next() { var user User // ScanRows is a method of `gorm.DB`, it can be used to scan a row into a struct db.ScanRows(rows, &user) // do something }
FindInBatches
批量查询和处理记录
// batch size 100 result := db.Where("processed = ?", false).FindInBatches(&results, 100, func(tx *gorm.DB, batch int) error { for _, result := range results { // batch processing found records } tx.Save(&results) tx.RowsAffected // number of records in this batch batch // Batch 1, 2, 3 // returns error will stop future batches return nil }) result.Error // returned error result.RowsAffected // processed records count in all batches |
查询挂钩
GORM允许对查询使用AfterFind钩子,查询记录时会调用,详情参考Hooks
func (u *User) AfterFind(tx *gorm.DB) (err error) { if u.Role == "" { u.Role = "user" } return }
采摘(Pluck)
从数据库中查询单列并扫描成一个切片,如果要查询多列,请使用 Select with Scan 代替
var ages []int64 db.Model(&users).Pluck("age", &ages) var names []string db.Model(&User{}).Pluck("name", &names) db.Table("deleted_users").Pluck("name", &names) // Distinct Pluck db.Model(&User{}).Distinct().Pluck("Name", &names) // SELECT DISTINCT `name` FROM `users` // Requesting more than one column, use `Scan` or `Find` like this: db.Select("name", "age").Scan(&users) db.Select("name", "age").Find(&users) |
范围
范围允许您指定可以作为方法调用引用的常用查询
func AmountGreaterThan1000(db *gorm.DB) *gorm.DB { return db.Where("amount > ?", 1000) } func PaidWithCreditCard(db *gorm.DB) *gorm.DB { return db.Where("pay_mode_sign = ?", "C") } func PaidWithCod(db *gorm.DB) *gorm.DB { return db.Where("pay_mode_sign = ?", "C") } func OrderStatus(status []string) func (db *gorm.DB) *gorm.DB { return func (db *gorm.DB) *gorm.DB { return db.Where("status IN (?)", status) } } db.Scopes(AmountGreaterThan1000, PaidWithCreditCard).Find(&orders) // Find all credit card orders and amount greater than 1000 db.Scopes(AmountGreaterThan1000, PaidWithCod).Find(&orders) // Find all COD orders and amount greater than 1000 db.Scopes(AmountGreaterThan1000, OrderStatus([]string{"paid", "shipped"})).Find(&orders) // Find all paid, shipped orders that amount greater than 1000
结帐范围以了解详细信息
数数
获取匹配的记录数
var count int64 db.Model(&User{}).Where("name = ?", "jinzhu").Or("name = ?", "jinzhu 2").Count(&count) // SELECT count(1) FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2' db.Model(&User{}).Where("name = ?", "jinzhu").Count(&count) // SELECT count(1) FROM users WHERE name = 'jinzhu'; (count) db.Table("deleted_users").Count(&count) // SELECT count(1) FROM deleted_users; // Count with Distinct db.Model(&User{}).Distinct("name").Count(&count) // SELECT COUNT(DISTINCT(`name`)) FROM `users` db.Table("deleted_users").Select("count(distinct(name))").Count(&count) // SELECT count(distinct(name)) FROM deleted_users // Count with Group users := []User{ {Name: "name1"}, {Name: "name2"}, {Name: "name3"}, {Name: "name3"}, } db.Model(&User{}).Group("name").Count(&count) count // => 3
- 登录 发表评论