GORM v1.30.0のジェネリクスAPI変更点|削除されたFirstOrCreate・Saveと移行のポイント
GORMのジェネリクスAPIは、Go Genericsに対応したv1.30.0で導入されました。この記事は、v1.30.0でのこの変更に絞って、何が新しくなり、どのAPIが削除され、既存コードをどう移行するかをまとめます。ジェネリクスAPIを使った基本的な実装パターン(gorm.G[T]でのCreate/Find/Update/Delete)は、GORMジェネリクスAPIを活用した基本的な実装パターンを参照してください。
まとめ
- GORMのジェネリクスAPIはv1.30.0で導入。
gorm.G[T]を起点に型安全な操作ができる。 - ジェネリクス版ではFirstOrCreateとSaveが意図的に削除された(曖昧さと並行性の問題を避けるため)。
- Saveの代わりにはCreateまたはUpdatesを使う。
gorm.DBインスタンスの使い回しに起因するSQL汚染を減らせるのも、この変更の狙い。
v1.30.0で導入されたジェネリクスAPIの位置づけ
v1.30.0で、GORMはGo Genericsを使ったAPIを正式にサポートしました。従来のdb.Model(&User{})のようにポインタとinterface{}を介する書き方に対し、ジェネリクス版はgorm.G[T]で型パラメータを明示するため、コンパイル時に型が固定され、戻り値も型付きで受け取れます。これにより型安全性が上がり、gorm.DBインスタンスを使い回した際に条件が意図せず引き継がれる「SQL汚染」も起きにくくなります。
v1.30.0で削除されたAPIとその理由
ジェネリクスAPIでは、FirstOrCreateとSaveが意図的に外されています。いずれも「状況によって挙動が変わる曖昧さ」や「並行実行時の競合」を招きやすいためです。特にSaveは、レコードが新規か既存かで内部的にINSERTとUPDATEを切り替えるため、どちらが実行されるかが呼び出し側から見えにくく、ジェネリクス版では提供されません。
削除されたAPIからの移行
Saveを使っていた箇所は、新規作成ならCreate、既存レコードの更新ならUpdatesに明示的に置き換えます。FirstOrCreateを使っていた「無ければ作る」処理は、まず取得を試み、無ければ作成する、という手順を自分で書くか、対象カラムを絞ったUpsert相当の実装に置き換えます。移行時は、暗黙にINSERT/UPDATEが切り替わっていた箇所を洗い出し、どちらの操作を意図していたかを明確にするのがポイントです。
バージョンの位置づけと最新化
ジェネリクスAPIはv1.30.0で導入されて以降のバージョンでも機能追加が続いています。関連(Association)操作やJoins・Preloadの拡張など、ジェネリクス版で扱える範囲は広がっているため、実際に採用する際は使用中のバージョンと公式ドキュメントで最新の対応状況を確認してください。
よくある質問
ジェネリクスAPIはどのバージョンから使えますか?
v1.30.0以降です。このバージョンでGORMがGo Genericsに正式対応し、gorm.G[T]を起点としたAPIが導入されました。
なぜSaveは削除されたのですか?
Saveは新規か既存かで内部的にINSERTとUPDATEを切り替えるため挙動が曖昧で、並行実行時にも問題を起こしやすいからです。ジェネリクスAPIでは提供されず、CreateまたはUpdatesの明示的な使用が推奨されます。
Saveの代わりには何を使えばよいですか?
新規作成はCreate、既存レコードの更新はUpdatesを使います。どちらを意図しているかをコード上で明確にすることが、移行のポイントです。
基本的な実装(CRUD)の書き方が知りたいです。
ジェネリクスAPIでのCreate/Find/Update/Deleteの基本パターンは、GORMジェネリクスAPIを活用した基本的な実装パターンにまとめています。