markdown

はじめに (対象読者・この記事でわかること)

この記事は、GoでWeb APIを開発していて「GORMのFindを実行してもDBの中身が取得できない」という問題に直面した方を対象としています。
記事を読むことで、なぜレコードが空になるのか、その根本原因と正しい構造体の定義方法、タグの付け方がわかります。今回はMySQLを例に解説しますが、PostgreSQLでも同じ考え方で解決できます。

前提知識

  • Goの基本的な文法が読める
  • GORMを使ったことがある(gorm.Openまでできている)
  • MySQLにテーブルが存在し、SELECT * FROM users;でデータが確認できる

GORMでFindしてもフィールドが空になる理由

GORMは構造体のフィールド名とDBのカラム名を自動でマッピングしようとします。
しかし、デフォルトの命名規則(スネークケース ↔ キャメルケース)を無視したカラム名を使っていると、マッピングが失敗します。結果、ゼロ値(文字列なら""、intなら0)のままになって「空っぽ」と見えるのです。

構造体のタグを正しく付けてマッピングを直す

実際のコードを見ながら、ステップごとに原因を切り分けて修正していきます。

ステップ1:問題の再現(空の構造体スライスが返る)

まず、以下のようなコードでFindを実行してみます。

Go
type User struct { ID uint UserName string Age int } var users []User db.Find(&users) fmt.Println(users) // [{0 0} {0 0} ...]

DBのテーブル定義は以下です。

Sql
CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, user_name VARCHAR(50), age INT );

このままではUserNameAgeがゼロ値のままです。

ステップ2:ログを確認してカラム名を確認する

GORMのログを有効にして、実際に発行されているSQLを確認しましょう。

Go
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{ Logger: logger.Default.LogMode(logger.Info), })

実行すると以下のようなログが出ます。

SELECT * FROM `users`

SQL自体は正しいのに、フィールドが空なので「マッピングがうまくいっていない」と推測できます。

ステップ3:gormタグで明示的にカラム名を指定する

構造体にgorm:"column:<カラム名>"タグを付けることで、マッピングを解決します。

Go
type User struct { ID uint `gorm:"column:id;primaryKey"` UserName string `gorm:"column:user_name"` Age int `gorm:"column:age"` }

これで再度db.Find(&users)を実行すると、正しく値が入ったスライスが取得できます。

ハマった点:プライマリーキーのタグを忘れるとUpdateが効かない

プライマリーキーがわからないと、GORMは「このレコードを特定できない」と判断してUPDATEやDELETEを実行しません。
gorm:"primaryKey"を忘れると、意図せずINSERTが走ることもあるので注意してください。

解決策:テーブル定義を構造体に正確に写す

  1. SHOW CREATE TABLE users;で正確なカラム名を確認
  2. 構造体フィールドにgorm:"column:<正確な名前>"を必ず付ける
  3. プライマリーキーはgorm:"primaryKey"を明記
  4. キャメルケースとスネークケースが一致しない場合はタグで上書き

まとめ

本記事では、GORMでFindしてもフィールドが空になる原因と、構造体にgorm:タグを正しく付けることで解決する方法を解説しました。

  • GORMのデフォルト命名規則を無視したカラム名を使っているとマッピング失敗
  • gorm:"column:<カラム名>"で明示的に紐付けるのが最短ルート
  • プライマリーキーはgorm:"primaryKey"で明示しておくとUPDATE/DELETEも安全

この知識があれば、既存のレガシーなDBでもGORMを使って安全に取り扱えます。次回は、プレロード(Preload)でリレーションを解決する方法を深掘りします。

参考資料