1
0

Go言語のGORMライブラリの規則でハマった(テーブル名編)

Posted at

はじめに

Go言語で開発されたORM (Object-Relational Mapping)ライブラリであるGORMで用いられるテーブル名に少しハマったのでメモしておきます。

GORMとは

Go言語で開発されたORM (Object-Relational Mapping)ライブラリです。

検証環境

こちらの記事で構築した環境を利用しました。

問題点(ハマったポイント

GORMライブラリのドキュメントには次のような記載がありました。

テーブル名: デフォルトでは、GORMは構造体名を スネークケース に変換し、テーブル名を複数形にします。 例えば、 User 構造体は、データベースの users テーブルになります。

これ、少し気になりますよね。

というのも、名詞の複数形にはいろいろな形があります。

単数名詞 複数名詞 意味 備考
product products 製品 -
country countries 子音 + -y
tomato tomatoes トマト 子音 + -o
shelf shelves -f, -fe
bus buses バス -s
tooth teeth 不規則変化
leaf leaves 不規則変化
fungus fungi 菌類 不規則変化
man men 不規則変化

単純な変化だけでなく、不規則変化する名詞もこの規則どおりの挙動になるのでしょうか。
今回はそれを確認していきます。

検証方法

今回は検証を行うだけなので、単数名詞の構造体を作成し、DBにテーブルは用意せずにDBアクセスして、SQLからテーブル名を確認してみました。

main.go
package main

import (
    "github.com/gin-gonic/gin"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
)


type Product struct { // 書き換えポイント1
  Id int
  Name string
}

func main() {
    engine:= gin.Default()
    engine.GET("/", func(c *gin.Context) {
        //DB接続
        dsn := "root@tcp(mysql:3306)/first?charset=utf8mb4&parseTime=True&loc=Local"
        db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
        if err != nil {
            panic("failed to connect database")
        }
        // レコードを1行取得
        db.First(&Product{}) // 書き換えポイント2
    })
    engine.Run(":8080")
}

検証結果

構造体名 SQL 考察
Product SELECT * FROM `products` ORDER BY `products`.`id` LIMIT 1 productsなので期待通り
Country SELECT * FROM `countries` ORDER BY `countries`.`id` LIMIT 1 countriesなので期待通り
Tomato SELECT * FROM `tomatoes` ORDER BY `tomatoes`.`id` LIMIT 1 tomatoesなので期待通り
Shelf SELECT * FROM `shelves` ORDER BY `shelves`.`id` LIMIT 1 shelvesなので期待通り
Bus SELECT * FROM `buses` ORDER BY `buses`.`id` LIMIT 1 busesなので期待通り

ここまでは通常の規則変化なので、期待値通りなのも頷けますね。

問題は不規則変化の名詞を用いた場合です。

構造体名 SQL 考察
Tooth SELECT * FROM `tooths` ORDER BY `tooths`.`id` LIMIT 1 teethにならずtoothsになってしまう
Leaf SELECT * FROM `leafs` ORDER BY `leafs`.`id` LIMIT 1 leavesにならずleafsになってしまう
Fungus SELECT * FROM `fungus` ORDER BY `fungus`.`id` LIMIT 1 fungiにならずfungusのまま
Man SELECT * FROM `men` ORDER BY `men`.`id` LIMIT 1 期待通りなのだが、上記の例があるのでこれが不規則変化するのは納得しづらい

まとめ

たとえGORMライブラリの規約に従ってDB設計を行ったとしても、不規則変化する名詞を用いる場合にはその限りではないようなので注意が必要というお話でした。

一応この規則の影響を受けない実装方法がいくつかあるので、それに利用するかどうかも含めてケースバイケースということですね。

Tips

テーブル名を直接指定する方法

db.Table("fungi").First(&Fungus{}) //  "SELECT * FROM `fungi` ORDER BY `fungi`.`id` LIMIT 1"になる

小規模なプログラムであればこれでも良いかもしれませんが、メンテナンス性は悪そうですね。

構造体とテーブル名を紐づける方法

// 構造体
type Fungus struct {
  Id int
  Name string
}

// 構造体と紐づくテーブル名を定義する
func (l *Fungus) TableName() string {
    return "fungi"
}

...

db.First(&Fungus{}) //  "SELECT * FROM `fungi` ORDER BY `fungi`.`id` LIMIT 1"になる

この使い方であればいちいち書き換える必要はありませんが、直感的でないところが問題ですね。

1
0
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
1
0