🕌

Go製のORM である Facebook / ent を使ってみたらなかなかイケてた話

2022/05/17に公開

はじめに

Facebookが開発しているGo製のORMであるentを業務で使い始めたので、基本的な構文などをまとめます。

導入

datetimeを更新しようとした際に発生したエラー

failed scanning rows: sql: Scan error on column index 8, name "updated_on": unsupported Scan, storing driver.Value type []uint8 into type *time.Time
	client, err := ent.Open("mysql", "root:pass@tcp(localhost:3307)/test?parseTime=true")

https://budougumi0617.github.io/2019/03/31/go_db_unsupported_scan_storing_driver_value_type_uint8_into_type_time_time/

リレーションを定義した別テーブルのカラムを取得する方法

まず、 Edgesの部分を以下の様に定義して、

ent/schema/archive_file.go

func (ArchiveFile) Edges() []ent.Edge {
	return []ent.Edge{
		edge.From("organization", OperatorCoMaster.Type).
		Ref("archiveFiles").
		Unique().
		Required().
		Field("operator_co_id"),
	}
}
ent/schema/operator_co_master.go

func (OperatorCoMaster) Edges() []ent.Edge {
	return []ent.Edge{
		edge.To("archiveFiles", ArchiveFile.Type),
	}
}

archivefileの全レコードを取得した後に、for文でoperatorCoMasterを一つずつ取り出せばいけた。

func toProtoArchive(af *ent.ArchiveFile, ocm *ent.OperatorCoMaster) *genproto.Archive {
	v := &genproto.Archive{
		Id: int32(af.ID),
		FileName: af.ArchiveFileName,
		FileTitle: af.ArchiveFileTitle,
		OperatorCoName: ocm.OperatorCoName,
	}
	return v
}

func (svc *ArchiveService) List(ctx context.Context, req *genproto.ListArchiveRequest) (*genproto.ListArchiveResponse, error) {
	archives, err := svc.client.ArchiveFile.Query().All(ctx)

	if err != nil {
		return nil, status.Errorf(codes.Internal, "internal: %s", err)
	}

	var keys []*genproto.Archive
	for _, v := range archives {
		operatorcomaster, _ := v.QueryOrganization().Only(ctx)
		po := toProtoArchive(v, operatorcomaster)

		keys = append(keys, po)
	}

	return &genproto.ListArchiveResponse{ArchiveList: keys}, nil
}

https://tech.smartcamp.co.jp/entry/try-go-ent

feature flug

go run entgo.io/ent/cmd/ent generate --feature sql/upsert ./ent/schema

migration

entのschemaファイルから生成されたマイグレーションファイルをDBに適用するためには golang-migrateを使用する必要があります。

apply migration

./migrations 以下に用意されたファイル内のクエリが実行されます。

  • upファイルのSQLがDBに実行される。
migrate -source file://migrations -database 'mysql://root:pass@tcp(localhost:3307)/test' up
  • downファイルのSQLがDBに実行される。
migrate -source file://migrations -database 'mysql://root:pass@tcp(localhost:3307)/test' down

force

特定のバージョンにまで戻す場合

migrate -source file://migrations -database 'mysql://root:pass@tcp(localhost:3307)/test' force {$VERSION}

https://github.com/golang-migrate/migrate

https://asapoon.com/golang/4002/golang-migrate/

db pull

既存DBにて既に定義ずみのテーブルを引っ張ってきたい場合にはentimportというパッケージを使用する必要があります。

https://entgo.io/ja/blog/2021/10/11/generating-ent-schemas-from-existing-sql-databases/

パッケージのインストール

go get ariga.io/entimport/cmd/entimport   

既存テーブルを持ってくる

go run ariga.io/entimport/cmd/entimport -dsn "mysql://root:pass@tcp(localhost:3307)/test" -tables client_account_master

fields

MySQLのカラムにマッピングする

ent側で用意されている型定義とMySQL側の型定義が若干違っている場合、以下の様にMySQL側の型定義に対してマッピングしてあげることができます。

	field.String("condition1").Optional().SchemaType(map[string]string{
			dialect.MySQL: "varchar(2)",
		}),

https://entgo.io/docs/schema-fields/#database-type

index

uniqeuキー制約をindex名称を明示した上で定義する

func (User) Indexes() []ent.Index {
    return []ent.Index{
		index.Fields("asp_id", "relation_unique_id", "client_site_id", "start_datetime").
			StorageKey("UNIQUE").
			Unique(),
    }
}

https://entgo.io/docs/schema-indexes#multiple-fields
https://entgo.io/docs/schema-indexes#storage-key

annotation

文字コードを明示する

ent/schema/user.go
func (User) Annotations() []schema.Annotation {
	return []schema.Annotation{
		entsql.Annotation{
			Collation: "utf8_general_ci",
			Charset: "utf8",
		},
	}
}

https://entgo.io/docs/faq/#how-to-change-the-character-set-andor-collation-of-a-mysql-table

テーブル名の指定

デフォルトではテーブル名が複数形になってしまうので、既にテーブルが作成済みでテーブル名を既存のもので指定したい場合には、以下の様にしてテーブル名を明示する必要があります。

ent/schema/user.go
func (User) Annotations() []schema.Annotation {
	return []schema.Annotation{
		entsql.Annotation{
			Table: "user",
		},
	}
}

https://entgo.io/docs/schema-annotations#custom-table-name

残念なところ

entでは複合primary keyを定義することができません。

entのschemaからER図を作成する

entのschemaファイルからER図を生成するためのツールが公開されています。

https://github.com/hedwigz/entviz

パッケージのインストール

go get github.com/hedwigz/entviz/cmd/entviz

ER図を生成する

go run github.com/hedwigz/entviz/cmd/entviz ./ent/schema

上記コマンドを実行すると以下のようなER図が自動生成されます。
シンプルなER図になっていてエンティティ間のリレーションが直感的にわかりやすいですね。

https://entgo.io/ja/blog/2021/08/26/visualizing-your-data-graph-using-entviz/

終わりに

公式ドキュメントに最低限の使用方法しか書かれておらず、開発を始めて間もない頃には、「なかなか開発速度が出ないなぁ」、という印象を持っていましたが、慣れてくるとサクサクと開発が進み、非常に良くできたフレームワークであることを実感しました。
今後開発を進めていく中で、他のユースケースも追記していきたいと思います。

Discussion