GORMで使うmodelの構造体をprivateにできるか
|
GORMで利用する構造体を下記のような形から
1type Hogehoge struct {
2 ID int `gorm:"id"`
3 Hoge string `gorm:"hoge"`
4 CreatedAt time.Time `gorm:"created_at"`
5 UpdatedAt time.Time `gorm:"updated_at"`
6}
次のような形にして、スコープを狭めることができないか調査しました。他の層で間違って参照されないように、スコープを狭めるのが狙いです。
1type hogehoge struct {
2 id int `gorm:"id"`
3 hoge string `gorm:"hoge"`
4 createdAt time.Time `gorm:"created_at"`
5 updatedAt time.Time `gorm:"updated_at"`
6}
結論
少し思っていたのとはちがいますが、下記のように定義することで、privateな構造体として定義しつつGORMでも利用できることがわかりました。
1type hogehoge struct {
2 ID int `gorm:"id"`
3 Hoge string `gorm:"hoge"`
4 CreatedAt time.Time `gorm:"created_at"`
5 UpdatedAt time.Time `gorm:"updated_at"`
6}
ご覧の通り、構造体の各フィールドのイニシャルは大文字にする必要があります。
構造体の各フィールドを大文字にしないといけない理由
GORMの処理で、各構造体がexportされているかをチェックする処理が有り、そこで引っかかってしまうためです。
1for i := 0; i < modelType.NumField(); i++ {
2 if fieldStruct := modelType.Field(i); ast.IsExported(fieldStruct.Name) {
3 if field := schema.ParseField(fieldStruct); field.EmbeddedSchema != nil {
4 schema.Fields = append(schema.Fields, field.EmbeddedSchema.Fields...)
5 } else {
6 schema.Fields = append(schema.Fields, field)
7 }
8 }
9}
GORMにParseWithSpecialTableName()
という関数が用意されていて、そこで↑の処理がかかれています。構造体のフィールドの頭文字を小文字にしてしまうと、IsExported()
でfalseが返ります。
IsExported()
は次のような処理になっていました。
1// IsExported reports whether name starts with an upper-case letter.
2func IsExported(name string) bool { return token.IsExported(name) }
IsExported()
でfalseになると、schema.Fieldsに値が入らないので、最終的に意図した処理ができなくなります。
まとめ
現在担当中のプロダクトをMVCモデルからレイヤードアーキテクチャに書き換えているのですが、その過程での調査です。今回は公式のドキュメントを読んでも分からなかったため、パッケージの中身をブレークポイント張ってデバッグしながら調査しました。良い勉強になりました。