2
1

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.

GoのGORMでiterate

Last updated at Posted at 2018-11-17

バッチ処理とかで大量のデータをループする場合の話

SQLクエリの結果をぜんぶarrayやsliceにしちゃったら、メモリに優しくないので。
Javaだと下記のような感じで、若手がよく陥るやつ。

ResultSet rs = ps.executeQuery(sql);
List<Hoge> list = new ArrayList<>();
while (rs.next) {
  Hoge h = new Hoge(rs.getString("fuga"));
  list.add(h);
}
return list;

GORMでもsql.Rowsを使う

rows, err := db.Model(&Hoge{}).Where("fuga = ?", "hige").Rows()
defer rows.Close()
for rows.Next() {
  var hoge Hoge
  db.ScanRows(rows, &hoge)
  // 何かいろいろ処理する
}

DB処理はRepositoryに分離して書きたい

sql.Rows を使うとこまでは、GORM Guideに書いてある。
クリーンアーキテクチャとか採用してて、DB処理をRepositoryに閉じ込めたい場合は、CallbackやIteratorを返す実装にする。

Callback方式

リポジトリ側

func (r *hogeRepositoryImpl) Iterate(callback func(h *Hoge) error) error {
  rows, err := r.db.Model(&Hoge{}).Where("fuga = ?", "hige").Rows()
  if err != nil {
    return err
  }

  defer rows.Close()
  for rows.Next() {
    var hoge Hoge
    r.db.ScanRows(rows, &hoge)
    // コールバックを呼んであげる
    err = callback(&hoge)
    if err != nil {
      return err
    }
  }

  return nil
}

リポジトリを使う側

func someCase(db *gorm.DB) error {
  repo := NewHogeRepository(db)

  repo.Iterate(func(h *Hoge) error {
    // Hogeを1個ずつ処理する
  })

  ...
}

Iteratorを返す方式

リポジトリ側

type HogeIterator struct {
  db   *gorm.DB
  rows *sql.Rows
}

func (i *HogeIterator) Next() bool {
  return i.rows.Next()
}

func (i *HogeIterator) Get() *Hoge {
  var hoge Hoge
  i.db.ScanRows(rows, &hoge)
  return hoge
}

func (i *HogeIterator) Close() {
  i.rows.Close()
}

func (r *hogeRepositoryImpl) Iterator() (*HogeIterator, error) {
  rows, err := r.db.Model(&Hoge{}).Where("fuga = ?", "hige").Rows()
  if err != nil {
    return nil, err
  }

  itr := &{ db: r.db, rows: rows }

  return itr, nil
}

リポジトリを使う側

func someCase(db *gorm.DB) error {
  repo := NewHogeRepository(db)

  itr, _ := repo.Iterator()
  defer itr.Close()
  for itr.Next() {
    hoge := itr.Get()
    // Hogeで何かする
  }

  ...
}

まとめ

Iteratorの方がめんどい。

2
1
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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?