ent 基本使用 三 边(关系处理)
ent 提供了图查询的能力,实际上在关系数据库中的表现就是relation,以下代码接前文
添加边(关系)
- 添加schema
entc init Car Group
效果: 
- 添加字段
car
package schema
import (
"github.com/facebookincubator/ent"
"github.com/facebookincubator/ent/schema/field"
)
// Car holds the schema definition for the Car entity.
type Car struct {
ent.Schema
}
// Fields of the Car.
func (Car) Fields() []ent.Field {
return []ent.Field{
field.String("model"),
field.Time("registered_at"),
}
}
// Edges of the Car.
func (Car) Edges() []ent.Edge {
return nil
}
Group
package schema
import (
"regexp"
"github.com/facebookincubator/ent"
"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").
// regexp validation for group name.
Match(regexp.MustCompile("[a-zA-Z_]+$")),
}
}
// Edges of the Group.
func (Group) Edges() []ent.Edge {
return nil
}
- 定义关系
以下是一个用户拥有多辆汽车,但是车只能拥有一个所有者

边定义(user schema)
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").
Positive(),
field.String("name").
Default("unknown"),
}
}
// Edges of the User.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("cars", Car.Type),
}
}
- 生成代码
entc generate ./ent/schema
效果 
- 创建car 处理
注意需要运行scheme 迁移
go run cmd/migration/main.go
package main
import (
"context"
"fmt"
"log"
"time"
_ "github.com/go-sql-driver/mysql"
"github.com/rongfengliang/ent-demo/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()
u, err := createCars(ctx, client)
if err != nil {
log.Fatal("some wrong", err)
} else {
log.Printf("user %s", u)
}
}
func createCars(ctx context.Context, client *ent.Client) (*ent.User, error) {
// creating new car with model "Tesla".
tesla, err := client.Car.
Create().
SetModel("Tesla").
SetRegisteredAt(time.Now()).
Save(ctx)
if err != nil {
return nil, fmt.Errorf("failed creating car: %v", err)
}
// creating new car with model "Ford".
ford, err := client.Car.
Create().
SetModel("Ford").
SetRegisteredAt(time.Now()).
Save(ctx)
if err != nil {
return nil, fmt.Errorf("failed creating car: %v", err)
}
log.Println("car was created: ", ford)
// create a new user, and add it the 2 cars.
a8m, err := client.User.
Create().
SetAge(30).
SetName("a8m").
AddCars(tesla, ford).
Save(ctx)
if err != nil {
return nil, fmt.Errorf("failed creating user: %v", err)
}
log.Println("user was created: ", a8m)
return a8m, nil
}
运行效果
go run cmd/edge/car/main.go
2019/10/14 14:26:06 car was created: Car(id=2, model=Ford, registered_at=2019-10-14 14:26:06.869078 +0800 CST m=+0.007888096)
2019/10/14 14:26:06 user was created: User(id=6, age=30, name=a8m)
2019/10/14 14:26:06 user User(id=6, age=30, name=a8m)
- 生成的ddl
car
CREATE TABLE `cars` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`model` varchar(255) COLLATE utf8mb4_bin NOT NULL,
`registered_at` timestamp NULL DEFAULT NULL,
`user_car_id` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `cars_users_cars` (`user_car_id`),
CONSTRAINT `cars_users_cars` FOREIGN KEY (`user_car_id`) REFERENCES `users` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
ER 模型 
- 查询car
func QueryCars(ctx context.Context, a8m *ent.User) error {
cars, err := a8m.QueryCars().All(ctx)
if err != nil {
return fmt.Errorf("failed querying user cars: %v", err)
}
log.Println("returned cars:", cars)
// what about filtering specific cars.
ford, err := a8m.QueryCars().
Where(car.ModelEQ("Ford")).
Only(ctx)
if err != nil {
return fmt.Errorf("failed querying user cars: %v", err)
}
log.Println(ford)
return nil
}
添加BackRef
实际上就是上边说的约束,一辆车只能有一个拥有着 
- 给car 对象添加边的约束
package schema
import (
"github.com/facebookincubator/ent"
"github.com/facebookincubator/ent/schema/edge"
"github.com/facebookincubator/ent/schema/field"
)
// Car holds the schema definition for the Car entity.
type Car struct {
ent.Schema
}
// Fields of the Car.
func (Car) Fields() []ent.Field {
return []ent.Field{
field.String("model"),
field.Time("registered_at"),
}
}
// Edges of the Car.
func (Car) Edges() []ent.Edge {
return []ent.Edge{
// create an inverse-edge called "owner" of type `User`
// and reference it to the "cars" edge (in User schema)
// explicitly using the `Ref` method.
edge.From("owner", User.Type).
Ref("cars").
// setting the edge to unique, ensure
// that a car can have only one owner.
Unique(),
}
}
- 生成代码
entc generate ./ent/schema
- 运行schema 迁移
go run cmd/migration/main.go
效果
ddl
CREATE TABLE `cars` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`model` varchar(255) COLLATE utf8mb4_bin NOT NULL,
`registered_at` timestamp NULL DEFAULT NULL,
`user_car_id` bigint(20) DEFAULT NULL,
`owner_id` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `cars_users_cars` (`user_car_id`),
CONSTRAINT `cars_users_cars` FOREIGN KEY (`user_car_id`) REFERENCES `users` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin

- 查询
cmd/edge/car/main.go
package main
import (
"context"
"fmt"
"log"
"time"
_ "github.com/go-sql-driver/mysql"
"github.com/rongfengliang/ent-demo/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()
u, err := createCars(ctx, client)
if err != nil {
log.Fatal("some wrong", err)
} else {
log.Printf("user %s", u)
}
QueryCarUsers(ctx, u)
}
func createCars(ctx context.Context, client *ent.Client) (*ent.User, error) {
// creating new car with model "Tesla".
tesla, err := client.Car.
Create().
SetModel("Tesla").
SetRegisteredAt(time.Now()).
Save(ctx)
if err != nil {
return nil, fmt.Errorf("failed creating car: %v", err)
}
// creating new car with model "Ford".
ford, err := client.Car.
Create().
SetModel("Ford").
SetRegisteredAt(time.Now()).
Save(ctx)
if err != nil {
return nil, fmt.Errorf("failed creating car: %v", err)
}
log.Println("car was created: ", ford)
// create a new user, and add it the 2 cars.
a8m, err := client.User.
Create().
SetAge(30).
SetName("a8m").
AddCars(tesla, ford).
Save(ctx)
if err != nil {
return nil, fmt.Errorf("failed creating user: %v", err)
}
log.Println("user was created: ", a8m)
return a8m, nil
}
func QueryCarUsers(ctx context.Context, a8m *ent.User) error {
cars, err := a8m.QueryCars().All(ctx)
if err != nil {
return fmt.Errorf("failed querying user cars: %v", err)
}
// query the inverse edge.
for _, ca := range cars {
owner, err := ca.QueryOwner().Only(ctx)
if err != nil {
return fmt.Errorf("failed querying car %q owner: %v", ca.Model, err)
}
log.Printf("car %q owner: %q\n", ca.Model, owner.Name)
}
return nil
}
效果
go run cmd/edge/car/main.go
2019/10/14 14:54:08 car was created: Car(id=4, model=Ford, registered_at=2019-10-14 14:54:08.647003 +0800 CST m=+0.007479891)
2019/10/14 14:54:08 user was created: User(id=7, age=30, name=a8m)
2019/10/14 14:54:08 user User(id=7, age=30, name=a8m)
2019/10/14 14:54:08 car "Tesla" owner: "a8m"
2019/10/14 14:54:08 car "Ford" owner: "a8m"
创建m2m 的关系
需要实现的关系图如下:

- 添加边的处理
groups
package schema
import (
"regexp"
"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").
// regexp validation for group name.
Match(regexp.MustCompile("[a-zA-Z_]+$")),
}
}
// Edges of the Group.
func (Group) Edges() []ent.Edge {
return []ent.Edge{
edge.To("users", User.Type),
}
}
users
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").
Positive(),
field.String("name").
Default("unknown"),
}
}
// Edges of the User.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("cars", Car.Type),
edge.From("groups", Group.Type).
Ref("users"),
}
}
- 生成代码
entc generate ./ent/schema
- 运行模式迁移
go run cmd/migration/main.go
生成的er 模型,从图中我们可以看出是通过中间表解决m2m的问题,通过ent/migrate/schema.go 代码可以也看出来 
说明
以上是一个简单的关系处理的学习,后边会看看图查询的处理
参考资料
https://entgo.io/docs/getting-started/
https://github.com/rongfengliang/ent-demo
ent 基本使用 三 边(关系处理)的更多相关文章
- MySQL学习7 - 外键的变种 三种关系
一 介绍 二 如何找两张表之间的关系 三 表的三种关系 1.书和出版社 2.作者和书籍的关系 3.用户和博客 本节的重点 如何找出两张表之间的关系 表的三种关系 一 介绍 因为有foreign key ...
- Mysql -- 外键的变种 三种关系
一.介绍 因为有foreign key的约束, 使得两张表形成了三种关系 多对一 多对多 一对一 二.如果找出两张表之间的关系 #.先站在左表的角度去找 是否左表的多条记录可以对应右 ...
- python 全栈开发,Day62(外键的变种(三种关系),数据的增删改,单表查询,多表查询)
一.外键的变种(三种关系) 本节重点: 如何找出两张表之间的关系 表的三种关系 一.介绍 因为有foreign key的约束,使得两张表形成了三种了关系: 多对一 多对多 一对一 二.重点理解如果找出 ...
- day05-表的三种关系
表的三种关系 1)一对一 关联方式:foreign key+unique例如1个学生只能有1个学号,1个学号只能对应1个学生 #两张表: 学生表(student)和 学号表(student_id) # ...
- 完整性约束&外键变种三种关系&数据的增删改
完整性约束 本节重点: not null 与 default unique primary auto_increment foreign key 一.介绍 约束条件与数据类型的宽度一样,都是可选参数 ...
- mysql更新(五) 完整性约束 外键的变种 三种关系 数据的增删改
11-数据的增删改 本节重点: 插入数据 INSERT 更新数据 UPDATE 删除数据 DELETE 再来回顾一下之前我们练过的一些操作,相信大家都对插入数据.更新数据.删除数据有了全面的认识. ...
- mysq表的三种关系,数据的增删改以及单表多表查询
一丶三种关系 分析步骤: #.先站在左表的角度去找 是否左表的多条记录可以对应右表的一条记录,如果是,则证明左表的一个字段foreign key 右表一个字段(通常是id) #.再站在右表的角度去找 ...
- (转)Hibernate关联映射——对象的三种关系
http://blog.csdn.net/yerenyuan_pku/article/details/70148618 Hibernate关联映射——对象的三种关系 Hibernate框架基于ORM设 ...
- Mysql外键的变种 三种关系
一.介绍 因为有foreign key的约束,使得两张表形成了三种了关系: 多对一 多对多 一对一 二.重点理解如果找出两张表之间的关系 分析步骤: #1.先站在左表的角度去找 是否左表的多条记录可以 ...
- Spark 计算人员三度关系
1.一度人脉:双方直接是好友 2.二度人脉:双方有一个以上共同的好友,这时朋友网可以计算出你们有几个共同的好友并且呈现数字给你.你们的关系是: 你->朋友->陌生人 3.三度人脉:即你朋友 ...
随机推荐
- Prometheus 重新标签
Prometheus 重新标签 允许在采集之前对任何目标及其标签进行修改 • 重命名标签名 • 删除标签 • 过滤目标 action:重新标签动作 replace:默认,通过regex匹配source ...
- 通过Queue控制线程并发,并监控队列执行进度
# -*- coding:utf-8 -*- import Queue import time import threading # 需要执行的业务主体 def domain(id): time.sl ...
- 论文笔记:LightGBM: A Highly Efficient Gradient Boosting Decision Tree
引言 GBDT已经有了比较成熟的应用,例如XGBoost和pGBRT,但是在特征维度很高数据量很大的时候依然不够快.一个主要的原因是,对于每个特征,他们都需要遍历每一条数据,对每一个可能的分割点去计算 ...
- java基础 接口私有方法
/** * 问题描述: * 我们需要抽取一个共有方法,用来解决两个默认方法之间重复代码的问题 * 但是这个共有方法不应该让实现类使用,应该是私有化的. * * 解决方案: * 从java 9开始,接口 ...
- 将fileupload标签的值清空
在开发中遇到了这样一个问题,在一个form表单中,有一个fileupload标签,新增,修改都是同一个form,当我第一次选择了上传文件路径,并且提交之后,第二次再使用这个form,这次没有选择上传文 ...
- Spring Security 解析(五) —— Spring Security Oauth2 开发
Spring Security 解析(五) -- Spring Security Oauth2 开发 在学习Spring Cloud 时,遇到了授权服务oauth 相关内容时,总是一知半解,因此决 ...
- nginx 配置跨域
location / { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods 'GET, ...
- Ueditor 关于视频上传相关问题
!!!每次改动后记得,清除一下浏览器缓存再试 !!! 4点: 1.修复编辑时视频不能预览问题: 2.插入视频的时候.在预览的窗口提示 “输入的视频地址有误,请检查后再试!” 3.ueditor ...
- jQuery(三)之 选择器(基础版)
对于jQuery的调用,我们一般都会传入参数 html: <div></div> js: console.log($('<a />')); console.log( ...
- Web前端2019面试总结2
1.js继承: 想要继承,就必须要提供个父类(继承谁,提供继承的属性) 组合继承(组合原型链继承和借用构造函数继承)(常用) 重点:结合了两种模式的优点,传参和复用 特点:1.可以继承父类原型上的属性 ...