Ent框架教程:Todo应用的CRUD操作详解
前言
Ent是一个强大的Go语言实体框架,它通过代码生成的方式简化了数据库操作。本教程将带你使用Ent框架构建一个Todo应用,涵盖从基础CRUD操作到复杂查询的实现过程。
环境准备
在开始之前,请确保你已经:
- 安装了最新版本的Go语言环境
- 初始化了一个Go项目
- 通过包管理工具安装了Ent框架
创建基础Todo实体
首先,我们创建一个最简单的Todo实体,只包含ID字段:
func Example_Todo() {
// 初始化Ent客户端和上下文
client, ctx := setupClient()
// 创建Todo项
task1, err := client.Todo.Create().Save(ctx)
if err != nil {
log.Fatalf("创建Todo失败: %v", err)
}
fmt.Println(task1)
// 输出:
// Todo(id=1)
}
运行go test
命令验证代码是否正确执行。
扩展Todo字段
基础的Todo实体过于简单,我们为其添加更多实用字段:
func (Todo) Fields() []ent.Field {
return []ent.Field{
field.Text("text"). // 任务内容
NotEmpty(), // 不能为空
field.Time("created_at"). // 创建时间
Default(time.Now). // 默认为当前时间
Immutable(), // 不可修改
field.Enum("status"). // 任务状态
NamedValues(
"进行中", "IN_PROGRESS",
"已完成", "COMPLETED",
).
Default("IN_PROGRESS"), // 默认状态为"进行中"
field.Int("priority"). // 优先级
Default(0), // 默认优先级为0
}
}
修改后需要重新生成代码:
go generate ./ent
创建带字段的Todo项
现在我们可以创建更丰富的Todo项:
func Example_Todo() {
// 创建第一个Todo项
task1, err := client.Todo.Create().
SetText("添加GraphQL示例").
Save(ctx)
if err != nil {
log.Fatalf("创建Todo失败: %v", err)
}
fmt.Printf("%d: %q\n", task1.ID, task1.Text)
// 创建第二个Todo项
task2, err := client.Todo.Create().
SetText("添加Tracing示例").
Save(ctx)
if err != nil {
log.Fatalf("创建Todo失败: %v", err)
}
fmt.Printf("%d: %q\n", task2.ID, task2.Text)
// 输出:
// 1: "添加GraphQL示例"
// 2: "添加Tracing示例"
}
添加实体关系
在真实场景中,Todo项之间可能存在依赖关系。我们添加父子关系:
func (Todo) Edges() []ent.Edge {
return []ent.Edge{
edge.To("parent", Todo.Type). // 指向父Todo
Unique(). // 每个Todo只能有一个父项
From("children"), // 反向引用子Todo
}
}
同样需要重新生成代码:
go generate ./ent
建立Todo项关系
现在我们可以建立Todo项之间的依赖关系:
func Example_Todo() {
// 建立task2依赖于task1的关系
if err := task2.Update().
SetParent(task1).
Exec(ctx); err != nil {
log.Fatalf("建立Todo关系失败: %v", err)
}
// 输出:
// 1: "添加GraphQL示例"
// 2: "添加Tracing示例"
}
查询Todo项
查询所有Todo项
items, err := client.Todo.Query().All(ctx)
if err != nil {
log.Fatalf("查询Todo失败: %v", err)
}
for _, t := range items {
fmt.Printf("%d: %q\n", t.ID, t.Text)
}
查询有父项的Todo项
items, err := client.Todo.Query().
Where(todo.HasParent()). // 只查询有父项的Todo
All(ctx)
查询根Todo项(没有父项但有子项的Todo)
items, err := client.Todo.Query().
Where(
todo.Not(todo.HasParent()), // 没有父项
todo.HasChildren(), // 但有子项
).
All(ctx)
通过子项查询父项
parent, err := client.Todo.Query().
Where(todo.HasParent()). // 查询有父项的Todo
QueryParent(). // 向上查询父项
Only(ctx) // 只返回一个结果
if err != nil {
log.Fatalf("查询失败: %v", err)
}
fmt.Printf("%d: %q\n", parent.ID, parent.Text)
总结
通过本教程,我们学习了如何使用Ent框架:
- 创建基础实体
- 为实体添加各种类型的字段
- 建立实体之间的关系
- 执行各种查询操作
Ent框架的强大之处在于其类型安全和代码生成机制,这使得数据库操作更加直观和安全。在实际项目中,你可以基于这些基础知识构建更复杂的业务逻辑。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考