ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

如何用ent轻松遍历任意图结构:Traversals与Eager Load五大技巧

如何用ent轻松遍历任意图结构:Traversals与Eager Load五大技巧 如何用ent轻松遍历任意图结构Traversals与Eager Load五大技巧【免费下载链接】entAn entity framework for Go项目地址: https://gitcode.com/gh_mirrors/en/entent 是 Go 语言的实体框架An entity framework for Go它把数据建模为实体 边的图结构。本文带你用 5 个实用技巧掌握 ent 的图遍历Traversals与预加载Eager Load能力轻松查询任意深度的关联数据彻底告别 N1 查询烦恼。 先认识 ent 的顶点与边在 ent 中每个实体如User、Pet、Group都是一个顶点实体之间的关系叫边Edge。比如User → pets一个用户养多只宠物Group → admin一个群有一个管理员边一旦在 schema 定义 中声明ent 就会自动为你生成对应的遍历方法例如QueryAdmin()、QueryPets()、WithPets()。这是后续所有技巧的基础。官方文档对图遍历的完整讲解见doc/md/traversals.md技巧一方法链式调用实现多跳遍历 ⛓️ent 最直观的遍历方式就是把一串QueryXxx()方法链式连接起来。每一跳自动沿着边跳转owner, err : client.Group. Query(). Where(group.Name(Github)). // 1. 找到 Github 群 QueryAdmin(). // 2. 跳到管理员 Dan QueryFriends(). // 3. 跳到 Dan 的朋友 Ariel QueryPets(). // 4. 跳到 Ariel 的宠物 QueryFriends(). // 5. 再跳到宠物的朋友 Coco QueryOwner(). // 6. 最后拿到 Coco 的主人 Alex Only(ctx) // 期望只有一个结果 // 输出: User(id3, age37, nameAlex)只需 6 行代码就能跨越 5 个实体、遍历一张 5 层深的关系图。完整可运行示例位于 examples/traversal/example_test.go。 技巧链式调用中任何一跳都可以插入Where(...)过滤条件实现边遍历 边过滤。技巧二反向边查询从被关联方倒着找 ent 的边可以双向查询。Pet通过edge.From(owner, ...)定义了与User的反向边因此可以client.Pet.Query().QueryOwner()从宠物找到主人client.User.Query().QueryPets()从用户找到宠物同一个查询链的终点可以用不同方法取结果方法用途Only(ctx)期望恰好 1 条结果多于或少于都会报错All(ctx)取回所有结果sliceFirst(ctx)只取第一条Count(ctx)只统计数量不加载数据比如统计 Github 群管理员的所有朋友数只需把链尾换成Count(ctx)比加载全部实体高效得多。技巧三HasXxxWith 谓词按关系筛选实体 有时候你不只是想跳转而是想筛选出满足某种关系的实体。这时用HasXxxWith系列条件谓词。例如找出主人的朋友里有群管理员的所有宠物pets, err : client.Pet.Query(). Where( pet.HasOwnerWith( // 主人满足… user.HasFriendsWith( // 主人的朋友中有… user.HasManage(), // 是某个群的管理员 ), ), ). All(ctx) // 输出: [Pet(id1, namePedro) Pet(id2, nameXabi)]这些谓词可以任意嵌套组合表达三度关系以内这类复杂条件且底层只生成一条 SQL不会真的多次查库。类似的还有HasEdge(name, ...)等变体可按边名精确指定。技巧四WithXxx 预加载Eager Load一次查询搞定关联 这是解决N1 问题的核心技巧。假如你有 100 个用户逐个访问u.Edges.Pets会触发 100 次额外查询。而使用WithPets()后关联数据会在一次查询中被批量预加载到Edges字段中users, err : client.User. Query(). WithPets(). // 预加载每个用户的宠物 All(ctx) for _, u : range users { for _, p : range u.Edges.Pets { // 直接访问零额外查询 fmt.Printf(User(%v) - Pet(%v)\n, u.ID, p.ID) } }WithXxx方法支持对每个边单独使用一次查询可以同时预加载多个关联WithPets().WithGroups().WithFriends()。 官方详解doc/md/eager-load.mdx⚠️ 注意Eager Load 目前仅SQL 方言MySQL、Postgres、SQLite 等支持。技巧五嵌套预加载 自定义查询精细化控制 ️WithXxx还可以传入一个自定义查询函数在预加载的同时做过滤、排序、限流甚至可以嵌套多层admins, err : client.User. Query(). Where(user.Admin(true)). WithPets(). // 预加载全部宠物 WithGroups(func(q *ent.GroupQuery) { q.Limit(5) // 只取前 5 个群 q.WithUsers() // 每个群再嵌套预加载用户 }). All(ctx)执行后admin.Edges.Groups[i].Edges.Users已经有值了——三层关系一次搞定。对于 GraphQL 等需要同一条边、两组参数的场景ent 还提供WithNamedXxxAPI需开启namedges特性标志可用别名区分不同参数加载的同一边。⚙️ 性能小贴士为什么不是 JOIN由于一条 ent 查询可以预加载多个边ent 会为每个边额外执行查询而非单条大 JOIN文档中说明未来版本会持续优化。避免无谓深度嵌套With层数越多生成的查询越多按需加载即可。优先Count/ 谓词筛选能用HasXxxWith一条 SQL 解决的就不要链式加载全部实体。✅ 五大技巧速查清单#技巧代表 API适用场景1链式多跳遍历QueryAdmin().QueryFriends()...沿已知路径取终点数据2反向边 结果控制QueryOwner()、Only/All/Count从被关联方倒查、只取数量3关系谓词筛选HasOwnerWith(...)按复杂关系条件过滤4平铺预加载WithPets()解决 N1批量取关联5嵌套 自定义预加载WithGroups(func(q ...))多层关联 过滤/限流掌握这 5 个技巧你就已经能驾驭 ent 中绝大多数图查询场景。想动手练习可以从 examples/traversal/ 目录下的完整示例入手go test即可运行它覆盖了建图、遍历、事务等全流程。【免费下载链接】entAn entity framework for Go项目地址: https://gitcode.com/gh_mirrors/en/ent创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表