Ent代码生成工具链:从SQL到gRPC的代码生成之路
今天要给大家介绍的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。不过在操作前,我们要清楚工具的使用参数。
- 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
:以逗号分隔的表名列表,指定要检查的表,如果为空则表示检查所有表。
- 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进行一些修改。
- 修改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的message
;entproto.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代码生成工具链的使用有了更深入的了解,在实际开发中可以利用它高效地生成所需代码啦。