🏃

【Go】GORM v1.30 ジェネリクスAPIで型安全にレコードを削除する方法

に公開

はじめに

前回は、GORM v1.30で追加されたジェネリクスAPIで型安全にレコードを更新する方法について見ていきました。

今回は、同じくジェネリクスAPIを使って、型安全にレコードを削除する方法を見ていきます!

この記事でわかること

  • 従来のレコード削除方法とジェネリクスAPIでの削除方法の違い

ジェネリクスAPIを使ったレコードの削除

ここでは、ジェネリクスAPIを使ったレコードの削除方法を、従来の実装と比較しながら見ていきましょう。

1. レコードの削除

従来のレコードの削除は、以下のように実装することができます。

main.go
// 削除に関わる部分のみ抜粋
type User struct {
    ID        uint           `gorm:"primaryKey"`
    Name      string         `gorm:"not null"`
    Birthday  time.Time      `gorm:"type:date"`
}

birthday, _ := time.Parse(time.DateOnly, "2025-09-05")
user := User{ID: 8, Name: "Bob", Birthday: birthday}

// 主キーを指定し削除
db.Delete(&user)

実行されるSQLは以下のようになります。

# 主キーを指定し削除
[3.236ms] [rows:1] DELETE FROM "users" WHERE "users"."id" = 8

GORMでは、gorm.DeletedAtのフィールドが構造体に含まれている場合、物理削除ではなく論理削除が実行されるようになります。
先ほどのコードにはgorm.DeletedAtのフィールドが存在しなかったためDELETEされましたが、存在する場合はUPDATEされます。

一方、ジェネリクスAPIを用いたレコードの削除は、以下のように実装することができます。

main.go
// 削除に関わる部分のみ抜粋
type User struct {
    ID        uint           `gorm:"primaryKey"`
    Name      string         `gorm:"not null"`
    Birthday  time.Time      `gorm:"type:date"`
    DeletedAt gorm.DeletedAt // 追加
}

// 主キーを指定し論理削除
row, err := gorm.G[User](db).Where("id = ?", 7).Delete(ctx)
if err != nil {
    log.Fatal(err)
}
fmt.Println("Row Affected:", row) // 出力結果→Row Affected: 1

実行されるSQLは以下の通りです。

## 主キーを指定し論理削除
UPDATE "users" SET "deleted_at"='2025-09-16 22:37:30.89' WHERE id = 7 AND "users"."deleted_at" IS NULL

Deleteメソッドを使う際は、条件を指定しないとエラーになります。
Global Deleteを防ぐためのガードとなっているので、条件を指定するようにしましょう。

また、ジェネリクスAPIでのDeleteメソッドのシグネチャは以下の通りです。

generics.go
func (c chainG[T]) Delete(ctx context.Context) (rowsAffected int, err error)

Deleteメソッドは、条件に合致するレコードを削除するメソッドです。

引数:
ctx: コンテキスト、処理のキャンセルやタイムアウトを制御するために使用

戻り値:
rowsAffected: 削除された行数、0の場合条件に合致するレコードが存在しないことを示す
err: 削除処理中に発生したエラー、正常に更新できた場合はnil

まとめ

今回は、GORM v1.30で追加されたジェネリクスAPIを使って、型安全にレコードを削除する方法を見ていきました。

基本的な実装方法は、従来のものと大きくは違わないように見受けられます。

次回は、「ジェネリクスAPIのJoinsとPreload」について見ていきます!

参考

Discussion