今天要给大家介绍的Ent,是Facebook开源的一款Go语言ORM框架,它配备的代码生成工具链功能十分强大。借助这个工具链,我们可以实现从SQL生成schema,再由schema生成protobuf的message以及gRPC的service,下面为大家详细讲解。

一、搭建项目基础

在使用Ent工具链前,得先创建一个Go项目,并初始化Ent相关的文件夹。

1.创建Go项目:在命令行中执行以下命令,创建一个名为entimport-example的Go项目:

go mod init entimport-example 

这个命令就像是给项目搭建了一个“框架”,为后续的开发工作做好准备。
2. 初始化Ent文件夹:接着,运行下面的命令来创建Ent的schema文件夹,它用于存放Ent的模式定义文件:

mkdir ./ent/schema 

这个文件夹就好比是项目中的一个“仓库”,专门用来存放与数据结构相关的重要信息。

二、从SQL生成schema

Ent工具链支持从SQL数据库中提取表结构,并生成相应的Ent schema。不过在操作前,我们要清楚工具的使用参数。

  1. Entimport工具参数说明entimport工具用于从SQL生成schema,它有几个重要参数:
    • -dsn:数据源名称,也就是数据库的连接信息。比如MySQL的连接信息格式为"mysql://user:pass@tcp(localhost:3306)/dbname" ,PostgreSQL的则是"postgres://user:pass@host:port/dbname"。这个参数就像是项目与数据库之间的“桥梁”,让程序知道该连接哪个数据库。
    • -exclude-tables:以逗号分隔的表名列表,表示要排除的表。
    • -schema-path:Ent schema的输出路径,默认是"./ent/schema"
    • -tables:以逗号分隔的表名列表,指定要检查的表,如果为空则表示检查所有表。
  2. MySQL数据库操作示例:假设我们有如下MySQL数据库表结构:
CREATE TABLE users ( id bigint auto_increment PRIMARY KEY, age bigint NOT NULL, name varchar(255) NOT NULL, last_name varchar(255) NULL comment 'surname' ); CREATE TABLE cars ( id bigint auto_increment PRIMARY KEY, model varchar(255) NOT NULL, color varchar(255) NOT NULL, engine_size mediumint NOT NULL, user_id bigint NULL, CONSTRAINT cars_owners FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE SET NULL ); 

要导出这些表的结构生成Ent schema,在命令行执行:

go run -mod=mod ariga.io/entimport/cmd/entimport -dsn "mysql://root:pass@tcp(localhost:3306)/entimport" 

这里的命令就像是给工具下达的“指令”,告诉它从哪个MySQL数据库中提取表结构信息。
3. PostgreSQL数据库操作示例:PostgreSQL的表结构定义稍有不同,例如:

CREATE TABLE users ( id bigserial PRIMARY KEY, age bigint NOT NULL, name varchar(255) NOT NULL, last_name varchar(255) NULL ); CREATE TABLE cars ( id bigserial PRIMARY KEY, model varchar(255) NOT NULL, color varchar(255) NOT NULL, engine_size int NOT NULL, user_id bigint NULL, CONSTRAINT cars_owners FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL ); 

导出表结构的命令为:

go run -mod=mod ariga.io/entimport/cmd/entimport -dsn "postgres://postgres:123456@localhost:5432/entimport?sslmode=disable" 

通过这些操作,就能根据不同的SQL数据库表结构生成对应的Ent schema了。

三、从schema生成proto

生成Ent schema后,还能进一步生成proto文件,不过在此之前需要对生成的Schema进行一些修改。

  1. 修改Schema的Annotations方法:打开ent/schema/user.go文件,修改其中的Annotations方法,添加如下代码:
func (User) Annotations() []schema.Annotation { return []schema.Annotation{ entproto.Message(), entproto.Service( entproto.Methods( entproto.MethodCreate | entproto.MethodGet | entproto.MethodList | entproto.MethodBatchCreate ), ), } } 

这里的entproto.Message()就像是一个“标记”,告诉程序要为这个表生成proto的messageentproto.Service则表示要为该表生成gRPC的service;而entproto.Methods可以控制生成的service中包含哪些方法。
2. 为字段添加entproto.Field:同时,还要给每个字段添加entproto.Field,例如:

// Fields of the User. func (User) Fields() []ent.Field { return []ent.Field{ field.String("name"). Unique(). Annotations( entproto.Field(2), ), field.String("email_address"). Unique(). Annotations( entproto.Field(3), ), } } 

这一步就像是给每个字段贴上了特殊的“标签”,让生成proto文件时能准确处理每个字段。
3. 生成Ent代码和proto文件:修改完代码后,先执行以下命令生成Ent代码:

go run -mod=mod entgo.io/ent/cmd/ent generate ./schema 

然后再执行下面的命令生成proto文件:

go run -mod=mod entgo.io/contrib/entproto/cmd/entproto -path ./schema 

为了方便后续操作,我们可以把这两个命令写入到ent/generate.go文件中:

package ent //go:generate go run -mod=mod entgo.io/ent/cmd/ent generate ./schema //go:generate go run -mod=mod entgo.io/contrib/entproto/cmd/entproto -path ./schema 

之后,执行下面的命令就能一次性完成生成操作:

go generate ./... 

执行完上述操作后,会生成ent/proto目录,里面包含entpb文件夹,结构如下:

ent/proto └── entpb ├── entpb.proto └── generate.go 

不过,ent/proto/entpb/generate.go中的生成命令需要进行一些修改:

package entpb //go:generate protoc --go_out=.. --go-grpc_out=.. --go_opt=paths=source_relative --go-grpc_opt=paths=source_relative --entgrpc_out=.. --entgrpc_opt=paths=source_relative,schema_path=....schema entpb.proto 

修改后,利用这个文件就能从proto生成Go的代码。但在生成之前,还需要安装protoc的3个插件

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest go install entgo.io/contrib/entproto/cmd/protoc-gen-entgrpc@master 

完成插件安装后,再次执行go generate ./...,整个从SQL到gRPC的代码就全部生成完毕了。

通过以上详细介绍,相信大家对Ent代码生成工具链的使用有了更深入的了解,在实际开发中可以利用它高效地生成所需代码啦。