👋

gormでに更新処理における書き方による挙動の違い

2022/10/31に公開

はじめに

gormでは更新の書き方が複数あって、挙動がそれぞれ異なるのでまとめる

書き方と発行されるSQL

以下のようなテーブルの更新を考える

type Table struct {
	ID        int
	C1        string
	C2        string
	C3        *string
	UpdatedAt time.Time
	CreatedAt time.Time
}

1. Save

Saveメソッドを用いる場合

db.Save(&Table{
	ID: 1,
	C1: "hoge",
	C3: nil,
})

以下のようなSQLが発行される

UPDATE
  `tables`
SET
  `c1` = 'hoge',
  `c2` = '',
  `c3` = NULL,
  `updated_at` = '2022-10-30 23:11:15.142',
  `created_at` = '0000-00-00 00:00:00'
WHERE
  `id` = 1
  • ゼロ値への更新が可能
  • updated_atは更新してくれる

2. Updates

Updates メソッドを用いる場合

db.Updates(&Table{
	ID: 1,
	C1: "hoge",
	C3: nil,
})

以下のようなSQLが発行される

UPDATE
  `tables`
SET
  `c1` = 'hoge',
  `updated_at` = '2022-10-30 23:11:15.144'
WHERE
  `id` = 1
  • ゼロ値への更新はできない
  • updated_atは更新してくれる

3. Updates (with map)

Updates メソッドに、mapを渡す場合

db.Model(Table{}).
	Where("id = ?", 1).
	Updates(map[string]any{
		"C1": "hoge",
		"C3": nil,
	})

以下のようなSQLが発行される

UPDATE
  `tables`
SET
  `c1` = 'hoge',
  `c3` = NULL,
  `updated_at` = '2022-10-30 23:11:15.147'
WHERE
  id = 1
  • ゼロ値への更新は可能
  • updated_atは更新してくれる

4. Create (DUPLICATE KEY UPDTE)

Create を用いて以下のように更新する場合

db.
	Clauses(
		clause.OnConflict{
			Columns: []clause.Column{{Name: "id"}},
		},
	).
	Create(&Table{
		ID: 1,
		C1: "hoge",
		C3: nil,
	})

以下のようなSQLが発行される

INSERT INTO `tables`(
  `c1`,
  `c2`,
  `c3`,
  `updated_at`,
  `created_at`,
  `id`
)
VALUES(
  'hoge',
  '',
  NULL,
  '2022-10-30 23:11:15.149',
  '2022-10-30 23:11:15.149',
  1
)
ON DUPLICATE KEY UPDATE
  `id` = `id`
  • Saveと同じだがcreated_atも更新される挙動になる

今回の自分の場合

要件として、今回は以下の条件を満たしたかった

  • ゼロ値への更新は必要 → 1, 3, 4
  • created_atは都度指定したくない(更新されなくていい) → 3
  • updated_atは更新されてほしい → 1, 2, 3, 4

上記の条件であれば、3の書き方が都合が良かった

Discussion