ent 基本使用十五 一个图遍历的例子
以下是来自官方的一个user group pet 的查询demo
参考关系图

环境准备
- docker-compose mysql 环境
version: "3"
services:
mysql:
image: mysql:5.7.16
ports:
- 3306:3306
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
environment:
MYSQL_ROOT_PASSWORD: dalongrong
MYSQL_DATABASE: gogs
MYSQL_USER: gogs
MYSQL_PASSWORD: dalongrong
TZ: Asia/Shanghai
- golang mod 项目
go mod init github.com/rongfengliang/ent-pet-user-group
生成实体模型
- 生成schema
entc init Pet User Group
- 配置schema 字段以及边
pets
package schema
import (
"github.com/facebookincubator/ent"
"github.com/facebookincubator/ent/schema/edge"
"github.com/facebookincubator/ent/schema/field"
)
// Pet holds the schema definition for the Pet entity.
type Pet struct {
ent.Schema
}
// Fields of the Pet.
func (Pet) Fields() []ent.Field {
return []ent.Field{
field.String("name"),
}
}
// Edges of the Pet.
func (Pet) Edges() []ent.Edge {
return []ent.Edge{
edge.To("friends", Pet.Type),
edge.From("owner", User.Type).
Ref("pets").
Unique(),
}
}
user
package schema
import (
"github.com/facebookincubator/ent"
"github.com/facebookincubator/ent/schema/edge"
"github.com/facebookincubator/ent/schema/field"
)
// User holds the schema definition for the User entity.
type User struct {
ent.Schema
}
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
field.Int("age"),
field.String("name"),
}
}
// Edges of the User.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("pets", Pet.Type),
edge.To("friends", User.Type),
edge.From("groups", Group.Type).
Ref("users"),
edge.From("manage", Group.Type).
Ref("admin"),
}
}
group
package schema
import (
"github.com/facebookincubator/ent"
"github.com/facebookincubator/ent/schema/edge"
"github.com/facebookincubator/ent/schema/field"
)
// Group holds the schema definition for the Group entity.
type Group struct {
ent.Schema
}
// Fields of the Group.
func (Group) Fields() []ent.Field {
return []ent.Field{
field.String("name"),
}
}
// Edges of the Group.
func (Group) Edges() []ent.Edge {
return []ent.Edge{
edge.To("users", User.Type),
edge.To("admin", User.Type).
Unique(),
}
}
生成边以及定点数据
package main
import (
"context"
"fmt"
"log"
_ "github.com/go-sql-driver/mysql"
"github.com/rongfengliang/ent-pet-user-group/ent"
)
func main() {
client, err := ent.Open("mysql", "root:dalongrong@tcp(127.0.0.1)/gogs")
if err != nil {
log.Fatalf("failed opening connection to sqlite: %v", err)
}
defer client.Close()
ctx := context.Background()
Gen(ctx, client.Debug())
}
// Gen for generate demo datas
func Gen(ctx context.Context, client *ent.Client) error {
hub, err := client.Group.
Create().
SetName("Github").
Save(ctx)
if err != nil {
return fmt.Errorf("failed creating the group: %v", err)
}
// Create the admin of the group.
// Unlike `Save`, `SaveX` panics if an error occurs.
dan := client.User.
Create().
SetAge(29).
SetName("Dan").
AddManage(hub).
SaveX(ctx)
// Create "Ariel" and its pets.
a8m := client.User.
Create().
SetAge(30).
SetName("Ariel").
AddGroups(hub).
AddFriends(dan).
SaveX(ctx)
pedro := client.Pet.
Create().
SetName("Pedro").
SetOwner(a8m).
SaveX(ctx)
xabi := client.Pet.
Create().
SetName("Xabi").
SetOwner(a8m).
SaveX(ctx)
// Create "Alex" and its pets.
alex := client.User.
Create().
SetAge(37).
SetName("Alex").
SaveX(ctx)
coco := client.Pet.
Create().
SetName("Coco").
SetOwner(alex).
AddFriends(pedro).
SaveX(ctx)
fmt.Println("Pets created:", pedro, xabi, coco)
// Output:
// Pets created: Pet(id=1, name=Pedro) Pet(id=2, name=Xabi) Pet(id=3, name=Coco)
return nil
}
一些查询
为了方便查看生成的sql 我使用了debug,同时也可以开启慢查询
set global slow_query_log=1;
set global long_query_time=0;
- 一个demo
上面的遍历从一个Group实体开始,继续到其admin(边),继续到其friends(边),获取其pets(边),获取每个宠物的
friends(边),并请求其所有者
参考图
代码:
func Traverse(ctx context.Context, client *ent.Client) error {
owner, err := client.Group. // GroupClient.
Query(). // Query builder.
Where(group.Name("Github")). // Filter only Github group (only 1).
QueryAdmin(). // Getting Dan.
QueryFriends(). // Getting Dan's friends: [Ariel].
QueryPets(). // Their pets: [Pedro, Xabi].
QueryFriends(). // Pedro's friends: [Coco], Xabi's friends: [].
QueryOwner(). // Coco's owner: Alex.
Only(ctx) // Expect only one entity to return in the query.
if err != nil {
return fmt.Errorf("failed querying the owner: %v", err)
}
fmt.Println(owner)
// Output:
// User(id=3, age=37, name=Alex)
return nil
}
效果:
2019/10/15 13:10:12 driver.Query: query=SELECT DISTINCT `users`.`id`, `users`.`age`, `users`.`name` FROM `users` JOIN (SELECT `pets`.`owner_id` FROM
`pets` JOIN (SELECT `pet_friends`.`friend_id` FROM `pet_friends` JOIN (SELECT `pets`.`id` FROM `pets` JOIN (SELECT `users`.`id` FROM `users` JOIN (
SELECT `user_friends`.`friend_id` FROM `user_friends` JOIN (SELECT `users`.`id` FROM `users` JOIN (SELECT `groups`.`admin_id` FROM `groups` WHERE `g
roups`.`name` = ?) AS `t1` ON `users`.`id` = `t1`.`admin_id`) AS `t1` ON `user_friends`.`user_id` = `t1`.`id`) AS `t1` ON `users`.`id` = `t1`.`frien
d_id`) AS `t1` ON `pets`.`owner_id` = `t1`.`id`) AS `t1` ON `pet_friends`.`pet_id` = `t1`.`id`) AS `t1` ON `pets`.`id` = `t1`.`friend_id`) AS `t1` O
N `users`.`id` = `t1`.`owner_id` LIMIT ? args=[Github 2]
User(id=3, age=37, name=Alex)
sql 查询计划
EXPLAIN SELECT
DISTINCT `users`.`id`,
`users`.`age`,
`users`.`name`
FROM
`users`
JOIN (
SELECT
`pets`.`owner_id`
FROM
`pets`
JOIN (
SELECT
`pet_friends`.`friend_id`
FROM
`pet_friends`
JOIN (
SELECT
`pets`.`id`
FROM
`pets`
JOIN (
SELECT
`users`.`id`
FROM
`users`
JOIN (
SELECT
`user_friends`.`friend_id`
FROM
`user_friends`
JOIN (
SELECT
`users`.`id`
FROM
`users`
JOIN (
SELECT
`groups`.`admin_id`
FROM
`groups`
WHERE
`groups`.`name` = 'Github'
) AS `t1` ON `users`.`id` = `t1`.`admin_id`
) AS `t1` ON `user_friends`.`user_id` = `t1`.`id`
) AS `t1` ON `users`.`id` = `t1`.`friend_id`
) AS `t1` ON `pets`.`owner_id` = `t1`.`id`
) AS `t1` ON `pet_friends`.`pet_id` = `t1`.`id`
) AS `t1` ON `pets`.`id` = `t1`.`friend_id`
) AS `t1` ON `users`.`id` = `t1`.`owner_id`
效果:

- 另外一个demo
我们要获取所有owner(edge)是friend 某个组admin(边)的宠物(实体)。
func Traverse(ctx context.Context, client *ent.Client) error {
pets, err := client.Pet.
Query().
Where(
pet.HasOwnerWith(
user.HasFriendsWith(
user.HasManage(),
),
),
).
All(ctx)
if err != nil {
return fmt.Errorf("failed querying the pets: %v", err)
}
fmt.Println(pets)
// Output:
// [Pet(id=1, name=Pedro) Pet(id=2, name=Xabi)]
return nil
}
效果
go run cmd/query2/main.go
2019/10/15 13:18:47 driver.Query: query=SELECT DISTINCT `pets`.`id`, `pets`.`name` FROM `pets` WHERE `pets`.`owner_id` IN (SELECT `id` FROM `users`
WHERE `users`.`id` IN (SELECT `user_friends`.`user_id` FROM `user_friends` JOIN `users` AS `t0` ON `user_friends`.`friend_id` = `t0`.`id` WHERE `t0`
.`id` IN (SELECT `admin_id` FROM `groups` WHERE `admin_id` IS NOT NULL))) args=[]
[Pet(id=1, name=Pedro) Pet(id=2, name=Xabi)]
查询计划
EXPLAIN SELECT
DISTINCT `pets`.`id`,
`pets`.`name`
FROM
`pets`
WHERE
`pets`.`owner_id` IN (
SELECT
`id`
FROM
`users`
WHERE
`users`.`id` IN (
SELECT
`user_friends`.`user_id`
FROM
`user_friends`
JOIN `users` AS `t0` ON `user_friends`.`friend_id` = `t0`.`id`
WHERE
`t0`.`id` IN (
SELECT
`admin_id`
FROM
`groups`
WHERE
`admin_id` IS NOT NULL
)
)
)
效果 
参考资料
https://entgo.io/docs/traversals/
https://github.com/rongfengliang/ent-pet-user-group
ent 基本使用十五 一个图遍历的例子的更多相关文章
- PMP十五至尊图(第六版)
PMP(Project Management Professinoal)项目经理专业资格认证,由美国项目管理学会PMI(Project Management Institute)发起并组织的一种资格认 ...
- 第七十五课 图的遍历(DFS)
添加DFS函数: #ifndef GRAPH_H #define GRAPH_H #include "Object.h" #include "SharedPointer. ...
- 【PMP】十五至尊图
以上是PMP的10大知识领域与5个过程组,在PMP考试中属于必须记忆的知识,该知识来源于PMBOK 第6版 附件为每日练习记忆模板,可以更好的记忆上图 点击下载附件
- ExpandoObject与DynamicObject的使用 RabbitMQ与.net core(一)安装 RabbitMQ与.net core(二)Producer与Exchange ASP.NET Core 2.1 : 十五.图解路由(2.1 or earler) .NET Core中的一个接口多种实现的依赖注入与动态选择看这篇就够了
ExpandoObject与DynamicObject的使用 using ImpromptuInterface; using System; using System.Dynamic; names ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(十五)——集中式接口文档实现
之前有小伙伴在评论区留言说如何集成swagger,最开始没有想透给了对方一个似是而非的回答.实际上后来下来想了一下,用.NET5 提供的Source Generator其实可以很方便的实现接口集成.今 ...
- 第三十五个知识点:给针对ECDLP问题的Pollard rho,Pollard "Kangaroo",parallel Pollard rho攻击的一个粗略的描述
第三十五个知识点:给针对ECDLP问题的Pollard rho,Pollard "Kangaroo",parallel Pollard rho攻击的一个粗略的描述 我们的目标是对任 ...
- 使用Multiplayer Networking做一个简单的多人游戏例子-1/3(Unity3D开发之二十五)
猴子原创,欢迎转载.转载请注明: 转载自Cocos2Der-CSDN,谢谢! 原文地址: http://blog.csdn.net/cocos2der/article/details/51006463 ...
- 第四百一十五节,python常用排序算法学习
第四百一十五节,python常用排序算法学习 常用排序 名称 复杂度 说明 备注 冒泡排序Bubble Sort O(N*N) 将待排序的元素看作是竖着排列的“气泡”,较小的元素比较轻,从而要往上浮 ...
- 如鹏网学习笔记(十五)ASP.NET MVC核心基础笔记
一.ASP.Net MVC简介 1,什么是ASP.NET MVC? HttpHandler是ASP.net的底层机制,如果直接使用HttpHandler进行开发难度比较大.工作量大.因此提供了ASP. ...
随机推荐
- Linux VIM8.1 Python3 编辑器配置文件
Linux VIM8.1 Python3 编辑器配置文件 实现功能: 自动补全(包括函数模块方法补全) 自动代码标准格式化 自动检查代码错误 自定义头文件 自动括号补全 缩进指示线 代码一键折叠 代码 ...
- asp.net core 系列之Performance的 Response compression(响应压缩)
本文,帮助了解响应压缩的一些知识及用法(大部分翻译于官网,英文水平有限,不准确之处,欢迎指正). 什么是响应压缩?响应压缩简单的说就是为了减少网络带宽,而把返回的响应压缩,使之体积缩小,从而加快响应的 ...
- C# vb .net图像合成-合成椭圆
在.net中,如何简单快捷地实现图像合成呢,比如合成文字,合成艺术字,多张图片叠加合成等等?答案是调用SharpImage!专业图像特效滤镜和合成类库.下面开始演示关键代码,您也可以在文末下载全部源码 ...
- APS.NET MVC + EF (04)---路由和数据传递
4.1 视图引擎 ASP.NET MVC 提供两种视图引擎:ASPX(C#)和Razor(CSHTML),推荐使用Razor. 4.1.1 Razor的语法 在Razor视图中,所有的服务器端代码都是 ...
- T-SQL 批量更新字段
;WITH IdPhone AS ( SELECT * FROM(VALUES ('), ('), ('), ('), ('), ('), ('), ('), ('), (') ) AS v(Id, ...
- 【Java并发编程】24、Synchronized实现原理解析
一.概述 我们知道在JDK1.5之前synchronized是一个重量级锁,相对于j.u.c.Lock,它会显得那么笨重,以至于我们认为它不是那么的高效而慢慢摒弃它. 不过,随着后续Java版本更新对 ...
- jQuery绑定事件的四种方式:bind、live、delegate、on
1.jQuery操作DOM元素的绑定事件的四种方式 jQuery中提供了四种事件监听方式,分别是bind.live.delegate.on,对应的解除监听的函数分别是unbind.die.undele ...
- Android编译系统中的Android.bp
https://www.cnblogs.com/bluestorm/p/10895005.html Android.bp,是用来替换Android.mk的配置文件. 它使用Blueprint框架来解析 ...
- window界面自动化
一.windows带界面的自动化1.AutoIt AutoIt3官方下载地址:https://www.autoitscript.com/files/autoit3/autoit-v3-setup.ex ...
- 【Python】列表推导式
1. 列表推导式 list1 = [1, 3, 5, 6, 8] list2 = [x * 2 for x in list1] print(list2) # [2, 6, 10, 12, 16]