Go 用 ent 构建类型安全 ORM:实体定义、关联与代码生成
test12026-10-2915 次阅读
为什么选 ent
GORM 用反射在运行时拼查询,字段名写错要等跑起来才发现;sqlc 把 SQL 编译成 Go 但偏向手写 SQL。ent 走另一条路:用 Go 代码描述 schema,再用代码生成器产出带类型的方法和查询构造器,字段名、关联在编译期就确定。
一、定义实体
用 ent 的 schema 描述一个 User 与 Post 的一对多关系。
// ent/schema/user.go
package schema
import (
"entgo.io/ent"
"entgo.io/ent/schema/field"
"entgo.io/ent/schema/edge"
)
type User struct {
ent.Schema
}
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("name").NotEmpty(),
field.Int("age").Positive(),
}
}
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("posts", Post.Type),
}
}二、生成代码并查询
跑 ent generate 后,会得到一个带类型的客户端。查询时字段是编译期已知的,拼错字段名直接红。
client, _ := ent.Open("sqlite", "file:ent.db?cache=shared&_fk=1")
defer client.Close()
// 创建并连带创建帖子
u, _ := client.User.
Create().
SetName("Ada").
SetAge(30).
AddPosts(
client.Post.Create().SetTitle("hello").SaveX(ctx),
).
SaveX(ctx)
// 查某用户的所有帖子,posts 是强类型切片
posts, _ := u.QueryPosts().All(ctx)
for _, p := range posts {
_ = p.Title // 编译期已知字段
}三、用 predicate 做类型安全过滤
ent 为每个字段生成 predicate 函数,条件组合在编译期可检查,不会出现字符串拼错列名。
import "yourproject/ent/user"
users, _ := client.User.
Query().
Where(
user.AgeGT(18),
user.NameContains("A"),
).
Order(user.ByAge()).
All(ctx)四、迁移
ent 自带 migrate 包,启动时按 schema 自动建表,开发期很省心。
client.Schema.Create(ctx)小结
ent 的代价是要接受代码生成和一套自己的查询 DSL,换来的是字段与关联全程类型安全:改了 schema,调用方没跟着改就会编译失败。对字段多、关联复杂的业务,这份编译期担保很值。
T
test1
文章作者
为什么选 ent GORM 用反射在运行时拼查询,字段名写错要等跑起来才发现;sqlc 把 SQL 编译成 Go 但偏向...
- 分类
- 技术
- 发布时间
- 2026-10-29
- 字数
- 约 1355 字
- 阅读
- 15 次
