14
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

WHITEPLUSAdvent Calendar 2018

Day 18

Gormで書くRepositoryパターン

Last updated at Posted at 2018-12-17

この記事はWHITEPLUS Advent Calendar 2018 - Qiita 18日目になります。

こんにちは、WHITEPLUSのサーバーサイドエンジニア八巻です。 マネージャーをしながら、リネットの設計リードをしたりしています。

この記事の背景

リネットの環境ではGoのORMとしてGormを利用しています。
Goの環境ではレイヤードアーキテクチャに基いてDBへのアクセスをRepositoryパターンを実装することが多いのですが、ここでのGormの使い方が実装者によってバラバラなので、Repositoryパターンとしてはこれが良さそうというのをまとめてみました。
基本的に公式のドキュメントに書いてある内容になってます。
 (ドキュメントの中から適切な箇所探す出すの大変ですよね。。)

Repositoryパターン

ここで指しているリポジトリパターンはDDD(ドメイン駆動設計)の文脈で出てくるものを想定しています。
Repositoryの目的は大きく2つあります。

  • 集約(もしくはEntity)をDBへ「保存(save)」する
  • DBから集約(もしくはEntity)を「呼び出す(of)」

保存(save)

ドメインロジックで計算した結果のドメインオブジェクトを「保存」するとこが目的なので、insert or updateを透過的に扱えるようにします。
gormではAssignとFirstOrCreateを利用してこの機能を実装します。
ドキュメントは見つけづらいですが、Queryの中のAssignに記述があります。
http://doc.gorm.io/crud.html#query

// DTO
type User struct {
	ID   int `gorm:"primary_key"`
	Name string
	Age  int
}

// saveはgormのFirstOrCreateを使う
func (r *Repository) Save(u domain.User) error {
	return r.DB.Where(User{ID: u.ID.Int()}).
		Assign(User{
			Name: u.Name.String(),
			Age:  u.Age.Int()}).
		FirstOrCreate(&User{}).Error
}

この例ではUserIDが存在すれば更新(update)、存在しなければ登録(insert)されることになります。

呼び出し(of)

呼び出しに関しては、単純なものであればQueryで十分なのですが、いくつもテーブルをつなげてモデルを構築する際にはEager Loadingをしないと直ぐにN+1問題を発生させてしまします。
GormのドキュメントではPreLoadingとして紹介されてます。
http://doc.gorm.io/crud.html#preloading-eager-loading

type Order struct {
	ID       int `gorm:"primary_key"`
	Occurred time.Time
	Price    int
	User     User
	UserID   int
}

type User struct {
	ID   int `gorm:"primary_key"`
	Name string
	Age  int
}

func (r *Repository) Of(id id.OrderID) (out Order, err error) {
	err = r.DB.
		Where("id = ?", id.Int()).
		Preload("User").
		Find(&out).Error
	return
}

Orderの中のUserをこうすることで一緒にとってくることが出来ます。
今回の例ではないですが、Orderを複数とってくる場合は必要なuserをinでとって来てくれるので、N+1問題を防ぐことが出来ます。

まとめ

今回はGormの中でもRepositoryパターンにおいて使うと便利な機能を取り上げてみました。
Gormはシンプルながらも一通りのORMとしての機能が揃っていて、ドキュメントも充実してますので一度見直してみると新たな発見があって面白いです。

明日は来年の新卒?エンジニア@maaaasの「オブジェクト指向もわからない未経験がベンチャーIT企業に入社して2ヶ月でやったコト4つ」になります。

14
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?