我来为你介绍 GORM 中 SQL Expression 的公用方式让你能复用复杂的 SQL 表达式逻辑。核心方式使用 gorm.Expr 自定义函数GORM 的 Expr 方法允许你构建可复用的 SQL 表达式。1. 基础封装通用表达式函数package exprimport (fmtgorm.io/gorm)// 通用表达式构建器type SQLExpr struct {SQL stringVars []interface{}}func (e SQLExpr) Expression() string {return e.SQL}// 可复用的表达式函数 // DateEqual 日期相等处理时区/格式问题func DateEqual(column string, date string) *gorm.SqlExpr {return gorm.Expr(DATE(?) ?, gorm.Expr(column), date)}// JSONExtract JSON字段提取func JSONExtract(column, path string) *gorm.SqlExpr {return gorm.Expr(JSON_UNQUOTE(JSON_EXTRACT(?, ?)), gorm.Expr(column), path)}// Coalesce 空值处理func Coalesce(columns ...string) *gorm.SqlExpr {if len(columns) 0 {return nil}sql : COALESCE( columns[0]for i : 1; i len(columns); i {sql , columns[i]}sql )return gorm.Expr(sql)}// IfNull NULL值替换func IfNull(column string, defaultVal interface{}) *gorm.SqlExpr {return gorm.Expr(IFNULL(?, ?), gorm.Expr(column), defaultVal)}// Round 四舍五入func Round(column string, decimals int) *gorm.SqlExpr {return gorm.Expr(ROUND(?, ?), gorm.Expr(column), decimals)}// Concat 字符串拼接func Concat(columns ...string) *gorm.SqlExpr {sql : CONCAT(for i, col : range columns {if i 0 {sql , }sql ?}sql )exprs : make([]interface{}, len(columns))for i, col : range columns {exprs[i] gorm.Expr(col)}return gorm.Expr(sql, exprs...)}// AgeFromBirthday 根据生日计算年龄func AgeFromBirthday(birthdayCol string) *gorm.SqlExpr {return gorm.Expr(TIMESTAMPDIFF(YEAR, ?, CURDATE()),gorm.Expr(birthdayCol),)}// FullTextSearch 全文搜索MySQLfunc FullTextSearch(columns []string, keyword string) *gorm.SqlExpr {cols : for i, c : range columns {if i 0 {cols , }cols c}return gorm.Expr(fmt.Sprintf(MATCH(%s) AGAINST (? IN BOOLEAN MODE), cols),keyword,)}2. 使用方式package mainimport (expr // 上面定义的包gorm.io/gorm)type User struct {ID uintName stringBirthday *time.TimeProfile string gorm:type:jsonScore float64BackupName string}// 在查询中复用 // 查询计算年龄var users []struct {UserAge int}db.Model(User{}).Select(*, ?, expr.AgeFromBirthday(birthday)).Scan(users)// 查询JSON提取 空值处理db.Model(User{}).Where(? ?, expr.JSONExtract(profile, $.city), 北京).Find(users)// 查询使用Coalescedb.Model(User{}).Select(id, ? as display_name, expr.Coalesce(name, backup_name, 未知)).Find(users)// 查询分数四舍五入db.Model(User{}).Select(id, ? as rounded_score, expr.Round(score, 2)).Find(users)// 查询全文搜索db.Model(User{}).Where(? 0, expr.FullTextSearch([]string{name, profile}, gorm)).Find(users)3. 高级封装Scope 模式最推荐使用 GORM 的 Scopes 实现链式复用package scopesimport (gorm.io/gormyourapp/expr)// 可复用的 Scope 函数// WithAge 添加年龄计算字段func WithAge() func(db *gorm.DB) *gorm.DB {return func(db *gorm.DB) *gorm.DB {return db.Select(*, ? as age, expr.AgeFromBirthday(birthday))}}// WithDisplayName 添加显示名称处理空值func WithDisplayName() func(db *gorm.DB) *gorm.DB {return func(db *gorm.DB) *gorm.DB {return db.Select(*, ? as display_name,expr.Coalesce(name, backup_name),)}}// WhereCity 按城市筛选JSON字段func WhereCity(city string) func(db *gorm.DB) *gorm.DB {return func(db *gorm.DB) *gorm.DB {return db.Where(? ?, expr.JSONExtract(profile, $.city), city)}}// WhereActive 筛选活跃用户综合条件func WhereActive() func(db *gorm.DB) *gorm.DB {return func(db *gorm.DB) *gorm.DB {return db.Where(last_login_at DATE_SUB(NOW(), INTERVAL 30 DAY))}}// OrderByScore 按分数排序处理NULLfunc OrderByScore(desc bool) func(db *gorm.DB) *gorm.DB {return func(db *gorm.DB) *gorm.DB {order : ASCif desc {order DESC}return db.Order(gorm.Expr(? order, expr.Coalesce(score, 0)))}}使用 Scope// 链式组合高度复用db.Model(User{}).Scopes(scopes.WithAge(),scopes.WithDisplayName(),scopes.WhereCity(北京),scopes.WhereActive(),scopes.OrderByScore(true),).Find(users)// 也可以单独使用db.Model(User{}).Scopes(scopes.WithAge()).Find(users)4. 复杂表达式子查询封装package expr// SubQueryExpr 子查询表达式type SubQueryExpr struct {DB *gorm.DBAlias string}func (s SubQueryExpr) Expression() string {return fmt.Sprintf((%s) as %s, s.DB.ToSQL(func(db *gorm.DB) *gorm.DB {return db}), s.Alias)}// AvgScoreByGroup 分组平均分子查询func AvgScoreByGroup(groupCol string) *gorm.DB {return db.Model(User{}).Select(groupCol, AVG(score) as avg_score).Group(groupCol)}// RankByScore 分数排名子查询func RankByScore() *gorm.DB {return db.Model(User{}).Select(id, RANK() OVER (ORDER BY score DESC) as rank)}5. 完整实战示例package mainimport (gorm.io/gormyourapp/expryourapp/scopes)// 业务场景获取用户列表包含计算字段支持筛选和排序func GetUserList(ctx context.Context, req UserListReq) ([]UserDTO, error) {var result []UserDTOquery : db.Model(User{}).Scopes(scopes.WithAge(), // 复用计算年龄scopes.WithDisplayName(), // 复用显示名称)// 动态条件if req.City ! {query query.Scopes(scopes.WhereCity(req.City))}if req.ActiveOnly {query query.Scopes(scopes.WhereActive())}// 排序switch req.SortBy {case score:query query.Scopes(scopes.OrderByScore(req.Desc))case age:query query.Order(expr.AgeFromBirthday(birthday))}err : query.Find(result).Errorreturn result, err}总结对比方式 适用场景 复用级别expr 函数包 简单SQL表达式 表达式级Scopes 模式 完整的查询条件/字段 查询片段级子查询封装 复杂统计/排名 查询块级推荐实践将常用的表达式抽到 expr 包将完整的查询逻辑抽到 scopes 包这样可以在不同业务模块中灵活组合复用。