Go難しいです。gormは「なんでやねん」と思うことが多いです。
元Railsエンジニアには早すぎた技術なのかもしれません🥺
Many To Many周りの公式の記事が少しわかりにくくて、tipsを書いておきます
Many To Many (many2many)
gormではPreload()
する際に、構造体のフィールドのタグ(reflect.StructTag
)を仕込むことで、中間テーブルを簡単にORM側に理解させることができます。
普通の書き方
gorm内部的には、Field
という構造体でTagSettings map[string]string
で値を持っていて、全部大文字に変換してるのでmap[MANY2MANY:many2many:user_languages]
という感じで保存してあります
// usersテーブル
type User struct {
ID uint
Languages []*Language `gorm:"many2many:user_languages;"`
}
// languagesテーブル
type Language struct {
ID uint
Name string
}
// 中間テーブルの構造体を定義せずに、Eager Loadingが実行できる
DB.Model(&User{}).Preload("Languages")
テーブル名と構造体名が違う書き方
こういう書き方がGo的に良いか悪いかどうかは置いといて😅
Language
の構造体にフィールドを追加したくなくて、Language
と同じフィールドを持つLanguageWithOwn
を作成した時の、many2many
の書き方で
foreignKey, joinForeignKey, References, joinReferences
の4つを設定する必要があります
前述の通り、大文字小文字は内部で吸収されているので関係ないです。
// usersテーブル
type User struct {
ID uint
Languages []*OwnLanguage `gorm:"many2many:user_languages;foreignKey:id;joinForeignKey:user_id;References:id;joinReferences:language_id;"`
}
// foreignKey:id
// joinForeignKey:user_id
// References:id
// joinReferences:language_id
// languagesテーブル
type LanguageWithOwn struct {
ID uint
Name string
Own bool // 母国語かどうか
}
// 構造体とテーブル名を一致させる
func (l *LanguageWithOwn) TableName() string {
return "languages"
}
// Eager Loadingが実行され、User.Languagesに値が入る
DB.Model(&User{}).Preload("Languages")
あんまGoのライブラリのソース読まないけど、jsのライブラリとテイストは似てるなと思った(所感)