LoginSignup
22
14

More than 5 years have passed since last update.

GORMでデータベースを操作してみる

Last updated at Posted at 2018-12-25

「Tech Do Advent Calendar 2018」25日目、最終日です。
今回はgolangのORMライブラリであるgormの使い方を簡単にご紹介します。
この記事はGORM公式ページを参考にしています。

ORM(オブジェクト関係マッピング)とは?

wikipediaより

オブジェクト関係マッピング(英: Object-relational mapping、O/RM、ORM)とは、データベースとオブジェクト指向プログラミング言語の間の非互換なデータを変換するプログラミング技法である。オブジェクト関連マッピングとも呼ぶ。実際には、オブジェクト指向言語から使える「仮想」オブジェクトデータベースを構築する手法である。オブジェクト関係マッピングを行うソフトウェアパッケージは商用のものもフリーなものもあるが、場合によっては独自に開発することもある。

オブジェクト言語からデータベースへデータを渡すための橋渡しをするラッパー的なもの、らしいです。
golang ORM 略してgormです。
より詳しい説明は割愛。

説明の準備

今回説明に利用するデータはこちら。

テーブル名:employee

論理名 物理名 データ型 制約等
社員番号 emp_num integer 主キー、not null
社員名 emp_name varchar(255) not null
社員名のカナ emp_name_kana varchar(255)
年齢 age integer
入社日 hire_date timestamp not null
登録日 inserted_date timestamp not null

データ

emp_num emp_name emp_name_kana age hire_date inserted_date
1 hoge ホゲ 22 2018/04/01 2018/12/25
2 foo フー 30 2018/12/24 2018/12/25

とりあえず使ってみる

gormをインストール

go get -u github.com/jinzhu/gorm

操作対象となるデータの作成

//構造体を定義
type Employee struct {
    EmpNum       int            `gorm:"primary_key" "column:emp_num"`
    EmpName      string         `gorm:"column:emp_name"`
    EmpNameKana  sql.NullString `gorm:"column:emp_name_kana"`
    Age          sql.NullInt64  `gorm:"column:age"`
    HireDate     time.Time      `gorm:"column:hire_date"`
    InsertedDate time.Time      `gorm:"column:inserted_date"`
}

構造体の名称をテーブル名と同じ「employee」に。
各フィールド変数を、「{変数名} {型名} {gormの定義}」の形式で定義していきます。
gormの定義として、プライマリーキー、NOT NULL制約、型、カラム名等のタグを設定することが可能です。

注意点として、変数にNULL値が格納される場合、それに適応した変数型で定義する必要があります。
例:varchar型がNULL → sql.NullString
  timestamp型がNULL → pq.NullTime型  

//sql.NullStringの構造
type NullString struct {
    String    string
    Valid    bool
}

データベースのコネクション取得

db, err := gorm.Open("postgres", 
                     "host=localhost port=5432 user=hoge password=hogehoge dbname=hoge_db sslmode=disable")
    if err != nil {
        fmt.Println("error")
    }

//処理完了後クローズ
defer db.Close()

これで準備は完了。

Selectしてみる

//データを格納する変数を定義
employee := []Employee{}

//全取得
db.Find(&employee)

//表示
for _, emp := range employee {
    fmt.Println(emp.EmpNum)
    fmt.Println(emp.EmpName)
    fmt.Println(emp.EmpNameKana.String)
    fmt.Println(emp.Age.Int64)
    fmt.Println(emp.HireDate.Time)
    fmt.Println(emp.InsertedDate)
}

結果

1
hoge
ホゲ
22
2018-04-01 00:00:00 +0000 +0000
2018-12-25 00:00:00 +0000 +0000

実行例

実行例を少しだけ紹介

Select

最初の一行を取得

db.First(&employee)

全取得

db.Find(&employee)

条件に合致するデータを取得

db.Where("empName = ?", "hoge").Find(&employee)

条件に合致するデータを取得2

db.Where("age between ? and ?" "20", "30").Find(&employee)

いずれかの条件に合致するデータを取得

b.Where("empName = ?", "hoge").Or("empName = ?", "foo").Find(&employee)

取得カラムを指定して取得

db.Select("empName, hire_date").Find(&employee)

order by

db.Order("age desc").Find(&employee)

offset&limit

db.Offset(1).Limit(3).Find(&employee)

件数をカウント

var count int
db.Where("age > 20").Count(&count)

group&having

db.Select("empName, age").Group("age").Having("age > 25").Find(&employee)

Join

db.Table("employee emp")Join("inner join publisher pub on emp.publisher_id = pub.publisher_id")

Insert

データを挿入

//挿入するデータを定義
employee := Employee{EmpNum: 3,
                      EmpName: "bar",
                      EmpNameKana: sql.NullString{"バー", true},
                      Age: sql.NullInt64{int64(33), true},
                      HireDate: time.Now(),
                      InsertedDate: time.Now()
                     }

db.Create(&employee)

Update

データを更新


//更新するデータを定義
employee := Employee{EmpNum: 3,
                      EmpName: "bar",
                      EmpNameKana: sql.NullString{"バー", true},
                      Age: sql.NullInt64{int64(33), true},
                      HireDate: time.Now(),
                      InsertedDate: time.Now()
                     }

db.Save(&employee)

Delete

データを削除

db.Delete(&employee)

その他用法は公式ページで確認してください。

おまけ:開発中の失敗例と解決方法

実際に開発をしている中で想定通り動作しなかった例とその解決方法を挙げます。

取得対象のテーブル名が複数形になってしまう

取得したいテーブルは「employee」だが、実際に実行されるSQL分では「employees」になってしまっていたケース。

type employee struct{
    ...
}

//理想
select * from employee;

//実際
select * from employees;

原因は、gormのデフォルト設定で扱うテーブルは全て複数形で扱うようになっているため。

解決方法1:単数形で扱うように設定する

下記の記述を追加することで単数形のままSQLが実行されます。

db.SingularTable(true)

解決方法2:データベースの定義を複数形にする

gormによって複数形で扱われてしまうならデータベース側の定義を変えてしまおうという話です。
employee →employees

所感

gormを使わず素のSQL文を長々と書くよりも直感的に理解しやすい。
時間短縮にもなって良い。
gormが使える状況なら悩むことなく使うことをおすすめします。

22
14
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
22
14