别直接手写Go CRUD生成器,因sqlc、ent、gorm-gen已覆盖90%需求;自研易卡在类型映射、嵌套struct、数据库差异;仅强定制DTO、中间件或私有ORM时才需自研。

为什么别直接手写 Go CRUD 生成器
因为 sqlc、ent、gorm-gen 这类工具已经覆盖了 90% 的真实需求,自己从零写模板引擎+AST解析+SQL Schema 反射,大概率会卡在类型映射不全、嵌套 struct 生成失败、或 PostgreSQL/MySQL 类型差异上。真正需要“自研生成器”的场景极少——比如公司有强定制的 DTO 命名规范、必须注入特定中间件装饰器、或要对接私有 ORM 框架。
sqlc 生成 CRUD 的最小可行路径
它不运行时查 schema,而是靠 SQL 文件 + YAML 配置静态生成,稳定、无反射开销、IDE 友好。常见卡点不是不会用,而是没理清输入输出边界:
- SQL 文件里不能写
SELECT *,必须显式列出字段,否则sqlc无法推导 Go 字段名和类型 -
sqlc.yaml中的packages配置决定生成代码的包路径,若设为db,则所有生成文件都在./db/下,别误以为会自动建目录 - 执行
sqlc generate前,确保sqlc.json或sqlc.yaml和 SQL 文件在同一目录,否则报错no queries found - 生成的
CreateXXX方法参数是 struct 指针,传值会导致空指针 panic;而GetXXX返回的是值类型,不是指针
示例 SQL:
-- name: CreateUser :execresult INSERT INTO users (name, email) VALUES ($1, $2);
ent vs gorm-gen:选哪个取决于你是否要 runtime schema 管理
ent 是声明式(DSL in Go),适合需要自动迁移、图查询、权限策略等扩展能力的项目;gorm-gen 是 GORM 官方配套,只生成基于 *gorm.DB 的方法,轻量但深度绑定 GORM 生态。
- 用
ent要写ent/schema/user.go,定义字段、索引、边关系,再跑ent generate;它生成的Create方法返回*User,带完整链式构建能力 -
gorm-gen依赖已有 struct tag(如gorm:"column:name"),通过genny扫描 struct 生成方法,不处理外键约束或自动建表逻辑 - 二者都不支持 MySQL 的
JSON字段原生映射到 Gomap[string]interface{},需手动加Scanner/Valuer实现
自定义模板生成器最容易崩的三个地方
真要写自己的生成器(比如用 text/template + go/parser),别碰这三块:
立即学习“go语言免费学习笔记(深入)”;
- PostgreSQL 的
citext、jsonb、uuid类型,在database/sql中对应不同 Scan 方法,硬编码映射容易漏掉sql.NullString等可空变体 - 表名复数转换(
user→users)看似简单,但遇到news、status、series就得加白名单,否则生成出newss或statuuses - 嵌套结构体(如
User.Profile.Address)在 JOIN 查询中字段名会冲突,生成 struct 时若不做前缀隔离(如ProfileName、AddressCity),反序列化必错
实际项目里,宁可花半天调通 sqlc 的 overrides 配置,也别在生成器里重做类型系统。


















