gorm

最終更新:2020/05/25


目次

  1. gormとは
  2. 検索[単体]する
  3. 検索(複数)する
  4. カウント
  5. GROUP BY句を使う
  6. Rowsはなるべく使わない

1. gormとは

gormはGoのORMです。 習得しやすい、使いやすい、という総合力の高いライブラリで、GoでRDBのORMを使う場合はgormを選択されることが多いです。

RailsのActive Recordに似ているので、Railsの開発経験がある人だと早く使いこなせると思います。

2. 検索[単体]する

select文で単体のデータを取得する場合は、Findメソッドを使います。

// FindByID finds an employee object. func (impl userPersistenceImpl) FindByID(ID int) (*model.User, error) { user := &model.User{} if err := impl.db.Where("id = ?", ID).Find(user).Error; err != nil { return nil, err } return user, nil }

上記のメソッドは以下のようなSQLが発行されます。

select * from users where id = ?

Findメソッドはポインタを引数に取ります

メソッド化して結果を返すときは、そのままポインタを返すと良いでしょう。

理由はポインタの項目を参照ください。

3. 検索(複数)する

select文で複数のデータを取得する場合も、Findメソッドを使います。 検索結果を格納する変数に、配列オブジェクトを宣言します。

// FindByID finds employee objects. func (impl userPersistenceImpl) FindByID(companyID int) (*[]model.User, error) { users := &[]model.User{} if err := impl.db.Where("company_id = ?", companyID).Find(users).Error; err != nil { return nil, err } return user, nil }

以下のようなSQLが発行されます。

select * from users where company_id = ?

4. カウント

Count文でデータ件数を取得する場合は、Countメソッドを使います。

// CountByIDs counts users object. func (impl userPersistenceImpl) CountByIDs(IDs []int) (*[]model.User, error) { var count int if err := impl.db.Model(&model.User{}).Where("id IN (?)", IDs).Count(&count).Error; err != nil { return -1, err } return count, nil }

以下のようなSQLが発行されます。

select count(*) from users where id IN (?)

Countメソッドを使う場合、Modelメソッドでテーブルオブジェクトを指定する必要があります。

テーブルを指定しないとsqlのテーブルが発行されません。

ダメな場合

// FindByID finds an employee object. func (impl userPersistenceImpl) CountByIDs(IDs []int) (*[]model.User, error) { var count int if err := impl.db.Where("id IN (?)", IDs).Count(&count).Error; err != nil { return -1, err } return count, nil }

上記は以下のようなSQLが発行されます。

select count(*) from '' where id IN (?)

5. GROUP BY句を使う

SQLのGROUP BY句を発行するには以下のようなコードを書きます。

// GroupByProductID finds Result. func (r *IOrdersRepositoryImpl) GroupByProductID() (*[]model.Result, error) { results := &[]model.Result{} if err := r.db.Table("orders").Select("product_id, sum(quantity) as total_quantity").Group("product_id").Scan(&results).Error; err != nil { return nil, err } return results, nil }

上記のメソッドは以下のようなSQLが発行されます。

SELECT product_id, sum(quantity) as total_quantity FROM "orders" GROUP BY product_id

上記のコードを見ると、

生SQLに近いし、gormを使う意味があるのか

と思う人もいるでしょう。

実際、GROUP BY句に限ると、

gormのコードより生SQLの方がわかりやすい

といえます。

なので、Raw関数を使って

// GroupByProductID finds Result. func (r *IOrdersRepositoryImpl) GroupByProductID() (*[]model.Result, error) { results := &[]model.Result{} if err := r.db.Row("SELECT product_id, sum(quantity) FROM "orders" GROUP BY product_id").Scan(&results).Error; err != nil { return nil, err } return results, nil }

としても良いでしょう。

6. Rowsはなるべく使わない

gormにはRowsという関数が用意されています。

しかし、なるべく使うべきではありません。

理由は、

deffer close

の実装を忘れると、コネクションを掴んだままになって、コネクションプールが枯渇してしまうためです。

なので、アプリの場合だとクラッシュしてしまいます。

なので、Rowは余程の理由がない限り使用してはいけません。

Joinや生SQLで複雑なSQLの結果を取得するときは、データ取得用のstructを宣言して使います。

type struct Result { // feilds } var result := &[]Result{}

この変数にscanで格納すれば、コネクションプールの枯渇問題は発生しません。

impl.db.Row("複雑なSQL").Scan(&result)