动态构建 SQL 是常见需求。GORM 提供了灵活的构建方式,支持条件拼接、动态查询等场景。
GORM 的链式 API 本身就是 SQL 构建器:
query := db.Model(&User{})
if name != "" {
query = query.Where("name LIKE ?", "%"+name+"%")
}
if status != "" {
query = query.Where("status = ?", status)
}
if minAge > 0 {
query = query.Where("age >= ?", minAge)
}
var users []User
query.Find(&users)
封装条件构建逻辑:
type QueryBuilder struct {
db *gorm.DB
}
func NewQueryBuilder(db *gorm.DB) *QueryBuilder {
return &QueryBuilder{db: db}
}
func (qb *QueryBuilder) Where(condition string, args ...interface{}) *QueryBuilder {
qb.db = qb.db.Where(condition, args...)
return qb
}
func (qb *QueryBuilder) If(condition bool, fn func(*QueryBuilder) *QueryBuilder) *QueryBuilder {
if condition {
return fn(qb)
}
return qb
}
func (qb *QueryBuilder) Find(dest interface{}) error {
return qb.db.Find(dest).Error
}
// 使用
var users []User
NewQueryBuilder(db.Model(&User{})).
If(name != "", func(qb *QueryBuilder) *QueryBuilder {
return qb.Where("name LIKE ?", "%"+name+"%")
}).
If(status != "", func(qb *QueryBuilder) *QueryBuilder {
return qb.Where("status = ?", status)
}).
Find(&users)
func BuildOrderBy(sortBy string, order string) string {
allowedFields := map[string]bool{
"id": true,
"name": true,
"created_at": true,
"updated_at": true,
}
allowedOrders := map[string]bool{
"asc": true,
"desc": true,
}
if !allowedFields[sortBy] {
sortBy = "id"
}
if !allowedOrders[order] {
order = "desc"
}
return sortBy + " " + order
}
db.Order(BuildOrderBy(params.SortBy, params.Order)).Find(&users)
func SelectFields(fields []string) interface{} {
if len(fields) == 0 {
return "*"
}
return fields
}
db.Select(SelectFields(params.Fields)).Find(&users)
query := db.Model(&User{})
if withOrders {
query = query.Joins("LEFT JOIN orders ON orders.user_id = users.id")
}
if withProfile {
query = query.Joins("LEFT JOIN profiles ON profiles.user_id = users.id")
}
query.Find(&results)
subQuery := db.Model(&Order{}).
Select("user_id, SUM(amount) as total").
Group("user_id").
Having("total > ?", 1000)
db.Table("(?) as o", subQuery).
Select("users.*, o.total").
Joins("JOIN users ON users.id = o.user_id").
Find(&results)
var activeUserScope = func(db *gorm.DB) *gorm.DB {
return db.Where("status = ?", "active").Where("deleted_at IS NULL")
}
var adultUserScope = func(db *gorm.DB) *gorm.DB {
return db.Where("age >= ?", 18)
}
db.Scopes(activeUserScope, adultUserScope).Find(&users)
搜索条件构建
func BuildSearchQuery(db *gorm.DB, params SearchParams) *gorm.DB {
query := db.Model(&User{})
if params.Keyword != "" {
query = query.Where("name LIKE ? OR email LIKE ?",
"%"+params.Keyword+"%",
"%"+params.Keyword+"%")
}
if len(params.Statuses) > 0 {
query = query.Where("status IN ?", params.Statuses)
}
if params.MinAge > 0 {
query = query.Where("age >= ?", params.MinAge)
}
if params.MaxAge > 0 {
query = query.Where("age <= ?", params.MaxAge)
}
if !params.StartTime.IsZero() {
query = query.Where("created_at >= ?", params.StartTime)
}
if !params.EndTime.IsZero() {
query = query.Where("created_at <= ?", params.EndTime)
}
if params.OrderBy != "" {
query = query.Order(params.OrderBy + " " + params.Order)
}
return query
}
统计查询构建
func BuildStatsQuery(db *gorm.DB, groupBy string, filters map[string]interface{}) *gorm.DB {
query := db.Model(&Order{})
for key, value := range filters {
if value != nil && value != "" {
query = query.Where(key+" = ?", value)
}
}
return query.Select(groupBy + ", COUNT(*) as count, SUM(amount) as total").
Group(groupBy).
Order("total DESC")
}
GORM 的 Clauses 提供更底层的构建能力:
import "gorm.io/gorm/clause"
db.Clauses(clause.OrderBy{
Columns: []clause.OrderByColumn{
{Column: clause.Column{Name: "age"}, Desc: true},
{Column: clause.Column{Name: "name"}},
},
}).Find(&users)
db.Clauses(clause.Locking{Strength: "UPDATE"}).Find(&users)
db.Clauses(clause.Limit{
Limit: 10,
Offset: 20,
}).Find(&users)
SQL 构建器让动态查询变得清晰。合理封装构建逻辑,提高代码复用性和可读性。