最終更新:2020/05/25
目次
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)