beego ORMで構造体にマッピングされずハマったこと


はじめに

goのwebframeworkであるbeegoにはORMの機能がついています。
これを使ってDBのテーブルから取得した値を構造体にマッピングしようとしたときに
マッピングされず小一時間ハマったことを共有します。
DBはSQLiteです。

前提条件

以下のようなテーブル(AUTH_MASTER)を構造体(AuthMaster)にマッピングするとします。

DBテーブルの定義。
AUTH_MASTER

列名
AUTH_ID integer
USER_ID integer
LOGIN_CODE text
CREATED_DATE text
CREATED_USER_ID integer
UPDATED_DATE text
UPDATED_USER_ID integer
ROW_VERSION integer

構造体の定義。
AuthMasterはCommonModelを埋め込んでいます。

authMaster.go
package models

import (
    _ "github.com/astaxie/beego/orm"
)

//AuthMaster comment
type AuthMaster struct {
    CommonModel
    AuthId int32 `orm:";pk"`
    UserId int32
    LoginCode string
    PasswordToken string
    EffectiveStartDate string
    ExpirationDate string
}
common.go
package models

import (
    "github.com/astaxie/beego/orm"
    _ "time"
)

//CommonModel comment
type CommonModel struct {
    CreatedDate   string
    CreatedUserId int32
    UpdatedDate   string
    UpdatedUserId int32
    RowVersion int32
}

beegoのormはデフォルトでスネークケースのDB列をアッパーキャメルケースの
構造体メンバにマッピングしてくれる仕様なので
https://beego.me/docs/mvc/model/models.md
AUTH_ID→AuthId
にマッピングしてくれるはず。
実行してみましょう。

マッピングされず

左の変数を見てもらうとわかりますが、構造体には何も入っていません。
(goはintegerの場合初期値0となります)
明らかにマッピングされていませんが、エラーも出ていない状態です。
なぜでしょうか・・・小一時間悩みました。

原因

DB列は小文字じゃないとマッピングされない!

beegoの仕様に落とし穴がありました。
仕様を見直すと

beegoのORMはデフォルトでスネークケースのDB列をアッパーキャメルケースの
構造体メンバにマッピングしてくれる

このスネークケースというのがポイントでした。
アッパースネークケースをマッピングするとは言ってない・・・!

AUTH_ID→アッパースネークケースだったのでマッピングされない、というのが真相です。
というわけでDBテーブルの定義を以下に修正してみましょう。

auth_master

列名
auth_id integer
user_id integer
login_code text
created_date text
created_user_id integer
updated_date text
updated_user_id integer
row_version integer

すると

無事マッピングされました!

別の回避方法

DBの列定義を変えたくないという場合は構造体の中でマッピングする列名を
明示的に書いてあげることでも回避可能です。

authMaster.go
package models

import (
    _ "github.com/astaxie/beego/orm"
)

//AuthMaster comment
type AuthMaster struct {
    CommonModel
    AuthId int32 `orm:";pk;column(AUTH_ID)"`
    UserId int32 `orm:"column(USER_ID)"`
    LoginCode string `orm:"column(LOGIN_CODE)"`
    PasswordToken string  `orm:"column(PASSWORD_TOKEN)"`
    EffectiveStartDate string  `orm:"column(EFFECTIVE_START_DATE)"`
    ExpirationDate string `orm:"column(EXPIRATION_DATE)"`
}

まとめ

スネークケースとアッパースネークケースは盲点でした。
両方ごっちゃになっていたという点とどちらもマッピングされるだろうという思い込み。
+DB定義はアッパースネークケースで定義するもの、という思い込みもありました。
思い込みダメ絶対。