0
Help us understand the problem. What are the problem?

posted at

updated at

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

はじめに

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")

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

まず、 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
}

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}

db pull

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

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

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)",
		}),

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",
		},
	}
}

テーブル名の指定

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

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

残念なところ

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

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

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

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

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

ER図を生成する

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

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

終わりに

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

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
0
Help us understand the problem. What are the problem?