gorm gen 的 mode 配置必须与实际调用方式严格对齐,否则导致 panic 或编译失败:withdefaultquery 需配 query.use(db),withoutcontext 要求方法不传 ctx,withqueryinterface 需手动实现或 withctx 包装,字段类型须用 fieldtype 统一映射。

直接上手就能用,但 90% 的人卡在生成后调用 panic 或编译失败——根本原因不是不会装工具,而是 Mode 配置和实际调用方式没对齐。
gen.WithDefaultQuery 必须配 query.Use(db) 初始化
生成的 query.User 是类型别名,不是可直接调用的对象。它背后依赖一个已初始化的 *gorm.DB 实例。
- 错误写法:
query.User.Where(...).Find()→ 编译通过但运行 panic “no db instance” - 正确写法:
query.Use(db).User.Where(...).Find(),其中db是你gorm.Open得到的实例 - 必须确保
query.Use(db)在真正调用前执行,不能放在init()里而db还是 nil - 如果项目用 wire/di 框架,建议把
query.Use(db)封装进 provider,避免多处重复调用
字段类型错位导致运行时 panic
MySQL 的 TINYINT(1) 默认映射为 int8,但 Go 字面量 1 是 int,传给 .Eq(1) 会因类型不匹配 panic。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 不要手动转:比如
q.Status.Eq(int8(1))—— 后续改逻辑时极易漏掉转换 - 统一用
gen.FieldType("status", "int")强制映射为int,适配业务层习惯 - 布尔字段优先用
gen.FieldType("is_active", "bool") + gen.FieldRelate("is_active", "Active"),避免uint8带来的== 1判断歧义 -
DECIMAL类型强烈建议映射为int64(单位“分”),再加json:"amount,string"tag 防止前端精度丢失
动态条件拼接必须用 []gen.Condition
不能靠 if/else 拼字符串,也不能用 map[string]interface{} 传参——GEN 的类型安全就断在这儿。
- 正确姿势:
var cond []gen.Condition,然后按需append(cond, q.Role.Eq(role)) - 最终统一传入:
q.Where(cond).Find(),GEN 会自动展开为 AND 条件 - 注意:空 slice
[]gen.Condition{}会被忽略,不会生成WHERE 1=1,这点比手写 SQL 安全 - 如果要 OR 条件,得用
gen.Or()包一层:q.Where(gen.Or(q.Name.Like("%a%"), q.Email.Like("%b%")))
生成路径和 module 名不一致引发 import 失败
OutPath: "../query" 看似合理,但若你的 go.mod module 名是 example.com/myapp,生成代码实际路径却是 ../query,Go 会认为这不是本模块包。
- IDE 提示
undefined: query,import "example.com/myapp/query"报错找不到包 - 解决方法:生成路径必须相对于 module 根目录,比如 module 是
example.com/myapp,就设OutPath: "query",生成到项目根下的query/目录 - 检查方式:
go list -m看当前 module 名,再确认query/是否在该 module 路径下 - CI 场景建议用 gentool 命令行而非
gen.go,避免路径硬编码问题
最常被忽略的一点:Mode 是契约,不是开关。你选了 gen.WithDefaultQuery | gen.WithQueryInterface,生成的代码就要求你必须用 query.Use(db);选了 gen.WithoutContext,所有方法签名就不带 context.Context——混用只会让编译器沉默、运行时爆炸。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










