##目次
はじめに
・はじめに
CRUD Interface
・Goでよく使われるgormを理解する:Query編
Associations
・Goでよく使われるgormを理解する:Associations編
・Goでよく使われるgormを理解する:Preloading編
#Preloading (Eager loading)
Preloadingは事前読み込みのことです。多くのormで実装されている機能ですが、gormでもPreload(struct's)
を指定することで、リソースを先読みしてキャッシュできるようなります。
##Preload
###Preloadを使わない場合
まずは、以下のようなstructを定義します。
type ActivityPlan struct {
Model
ActivityPlanName *string `gorm:"" json:"activityPlanName"`
Activities []*Activity `gorm:"many2many:activity_plan_activities" json:"activity"`
}
type Activity struct {
Model
ActivityName *string `gorm:"" json:"activityName"`
}
そして、DBからデータを取得するためのfunctionをActivityPlanモデルに作成し、まずはPreloadなしで実行してみます。
func GetAllActivityPlans() (ml []*ActivityPlan, err error) {
tx := db.Begin()
err = tx.Find(&ml).Commit().Error
return ml, err
}
[
{
"id": 1,
"createdAt": "2020-05-30T14:55:53+09:00",
"updatedAt": "2020-05-30T14:55:53+09:00",
"deletedAt": null,
"activityPlanName": "プランA",
"tourScheduleId": 1,
"activity": null
},
{
"id": 2,
"createdAt": "2020-05-30T14:55:53+09:00",
"updatedAt": "2020-05-30T14:55:53+09:00",
"deletedAt": null,
"activityPlanName": "プランB",
"tourScheduleId": 1,
"activity": null
},
〜 中略 〜
{
"id": 11,
"createdAt": "2020-05-30T14:55:53+09:00",
"updatedAt": "2020-05-30T14:55:53+09:00",
"deletedAt": null,
"activityPlanName": "プランK",
"tourScheduleId": 3,
"activity": null
},
{
"id": 12,
"createdAt": "2020-05-30T14:55:53+09:00",
"updatedAt": "2020-05-30T14:55:53+09:00",
"deletedAt": null,
"activityPlanName": "プランL",
"tourScheduleId": 3,
"activity": null
}
]
取得したデータを見てみると、activity_plansテーブルの関連先であるactivitiesテーブルの項目("activity")がnullになっており、自テーブルのデータしか取得できていないのがわかります。
以下のログを見ても、activity_plansテーブルのデータのみ全件取得していますね。
SELECT * FROM `activity_plans` WHERE `activity_plans`.`deleted_at` IS NULL[] 12
###Preloadを使った場合
では、Preloadを使用した場合はどうでしょう。
func GetAllActivityPlans() (ml []*ActivityPlan, err error) {
tx := db.Preload("Activities").Begin()
err = tx.Find(&ml).Commit().Error
return ml, err
}
[
{
"id": 1,
"createdAt": "2020-05-30T14:55:53+09:00",
"updatedAt": "2020-05-30T14:55:53+09:00",
"deletedAt": null,
"activityPlanName": "プランA",
"tourScheduleId": 1,
"activity": [
{
"id": 1,
"createdAt": "2020-05-30T14:55:52+09:00",
"updatedAt": "2020-05-30T14:55:52+09:00",
"deletedAt": null,
"activityName": "アクティビティA"
},
{
"id": 2,
"createdAt": "2020-05-30T14:55:52+09:00",
"updatedAt": "2020-05-30T14:55:52+09:00",
"deletedAt": null,
"activityName": "アクティビティB"
},
{
"id": 3,
"createdAt": "2020-05-30T14:55:52+09:00",
"updatedAt": "2020-05-30T14:55:52+09:00",
"deletedAt": null,
"activityName": "アクティビティC"
}
]
},
{
"id": 2,
"createdAt": "2020-05-30T14:55:53+09:00",
"updatedAt": "2020-05-30T14:55:53+09:00",
"deletedAt": null,
"activityPlanName": "プランB",
"tourScheduleId": 1,
"activity": [
{
"id": 2,
"createdAt": "2020-05-30T14:55:52+09:00",
"updatedAt": "2020-05-30T14:55:52+09:00",
"deletedAt": null,
"activityName": "アクティビティB"
},
{
"id": 3,
"createdAt": "2020-05-30T14:55:52+09:00",
"updatedAt": "2020-05-30T14:55:52+09:00",
"deletedAt": null,
"activityName": "アクティビティC"
},
{
"id": 4,
"createdAt": "2020-05-30T14:55:52+09:00",
"updatedAt": "2020-05-30T14:55:52+09:00",
"deletedAt": null,
"activityName": "アクティビティD"
}
]
},
〜 中略 〜
{
"id": 11,
"createdAt": "2020-05-30T14:55:53+09:00",
"updatedAt": "2020-05-30T14:55:53+09:00",
"deletedAt": null,
"activityPlanName": "プランK",
"tourScheduleId": 3,
"activity": [
{
"id": 2,
"createdAt": "2020-05-30T14:55:52+09:00",
"updatedAt": "2020-05-30T14:55:52+09:00",
"deletedAt": null,
"activityName": "アクティビティB"
},
{
"id": 4,
"createdAt": "2020-05-30T14:55:52+09:00",
"updatedAt": "2020-05-30T14:55:52+09:00",
"deletedAt": null,
"activityName": "アクティビティD"
},
{
"id": 5,
"createdAt": "2020-05-30T14:55:52+09:00",
"updatedAt": "2020-05-30T14:55:52+09:00",
"deletedAt": null,
"activityName": "アクティビティE"
}
]
},
{
"id": 12,
"createdAt": "2020-05-30T14:55:53+09:00",
"updatedAt": "2020-05-30T14:55:53+09:00",
"deletedAt": null,
"activityPlanName": "プランL",
"tourScheduleId": 3,
"activity": [
{
"id": 1,
"createdAt": "2020-05-30T14:55:52+09:00",
"updatedAt": "2020-05-30T14:55:52+09:00",
"deletedAt": null,
"activityName": "アクティビティA"
},
{
"id": 2,
"createdAt": "2020-05-30T14:55:52+09:00",
"updatedAt": "2020-05-30T14:55:52+09:00",
"deletedAt": null,
"activityName": "アクティビティB"
},
{
"id": 6,
"createdAt": "2020-05-30T14:55:52+09:00",
"updatedAt": "2020-05-30T14:55:52+09:00",
"deletedAt": null,
"activityName": "アクティビティF"
}
]
}
]
先ほどはnullだったactivitiesテーブルの項目("activity")も、データを取得できていることがわかります。
ちなみに、以下のログを確認すると、前回発行されていたactivity_plansテーブルのデータを取得するためのSQLに加えて、activitiesテーブルのデータを取得するためのSQLも発行されているようです。
中身を確認すると、中間テーブルであるactivity_plan_activitiesテーブルをactivitiesテーブルに内部結合して、activity_plan_activitiesテーブルのactivity_plan_idに指定したIDが含まれるかどうかを探しにいっているみたいですね。
SELECT * FROM `activity_plans` WHERE `activity_plans`.`deleted_at` IS NULL[] 12
SELECT * FROM `activities` INNER JOIN `activity_plan_activities` ON `activity_plan_activities`.`activity_id` = `activities`.`id` WHERE `activities`.`deleted_at` IS NULL AND ((`activity_plan_activities`.`activity_plan_id` IN (?,?,?,?,?,?,?,?,?,?,?,?)))[4 5 6 7 8 9 1 2 12 11 3 10] 0
##Auto Preloading
常に association を preload します
先ほどはアソシエーションを組んでいるモデルが一つだけでしたが、以下のように複数のモデルとアソシエーションを組んでいる場合はどうでしょう。
type User struct {
Model
UserName *string `gorm:"" json:"userName"` // ユーザー名
CompanyID *int `gorm:"" json:"companyId"` // 所属企業ID
Company *Company `gorm:"" json:"company"`
Languages []*Language `gorm:"many2many:user_languages;association_autoupdate:false" json:"language"` // 使用可能言語
}
type Language struct {
Model
LanguageName *string `gorm:"" json:"languageName"`
}
type Company struct {
Model
ConmpanyName *string `gorm:"" json:"companyName"`
}
もちろん、先ほど使用したPreload(struct's)
を複数つなげて、全てのstructを指定していくことも可能ですが、関連モデル全てに対してPreloadingしたい場合には、Set("gorm:auto_preload", true)
が有効です。
Set("gorm:auto_preload", true)
は以下のようにfunction側に設定を追加します。
func GetAllUsers() (ml []*User, err error) {
tx := db.Set("gorm:auto_preload", true).Begin()
err = tx.Find(&ml).Commit().Error
return ml, err
}
すると、以下のようにアソシエーションを組んでいるモデルの情報をすべてPreloadingすることができます。
[
{
"id": 1,
"createdAt": "2020-05-30T16:47:31+09:00",
"updatedAt": "2020-05-30T16:47:31+09:00",
"deletedAt": null,
"userName": "user1",
"companyId": 1,
"company": {
"id": 1,
"createdAt": "2020-05-30T16:47:29+09:00",
"updatedAt": "2020-05-30T16:47:29+09:00",
"deletedAt": null,
"companyName": "A株式会社"
},
"language": [
{
"id": 1,
"createdAt": "2020-05-30T16:47:29+09:00",
"updatedAt": "2020-05-30T16:47:29+09:00",
"deletedAt": null,
"languageName": "日本語"
}
]
},
{
"id": 2,
"createdAt": "2020-05-30T16:47:32+09:00",
"updatedAt": "2020-05-30T16:47:32+09:00",
"deletedAt": null,
"userName": "user2",
"companyId": 1,
"company": {
"id": 1,
"createdAt": "2020-05-30T16:47:29+09:00",
"updatedAt": "2020-05-30T16:47:29+09:00",
"deletedAt": null,
"companyName": "A株式会社"
},
"language": [
{
"id": 2,
"createdAt": "2020-05-30T16:47:29+09:00",
"updatedAt": "2020-05-30T16:47:29+09:00",
"deletedAt": null,
"languageName": "英語"
},
{
"id": 4,
"createdAt": "2020-05-30T16:47:29+09:00",
"updatedAt": "2020-05-30T16:47:29+09:00",
"deletedAt": null,
"languageName": "イタリア語"
}
]
},
{
"id": 3,
"createdAt": "2020-05-30T16:47:32+09:00",
"updatedAt": "2020-05-30T16:47:32+09:00",
"deletedAt": null,
"userName": "user3",
"companyId": 2,
"company": {
"id": 2,
"createdAt": "2020-05-30T16:47:29+09:00",
"updatedAt": "2020-05-30T16:47:29+09:00",
"deletedAt": null,
"companyName": "C株式会社"
},
"language": [
{
"id": 2,
"createdAt": "2020-05-30T16:47:29+09:00",
"updatedAt": "2020-05-30T16:47:29+09:00",
"deletedAt": null,
"languageName": "英語"
}
]
},
{
"id": 4,
"createdAt": "2020-05-30T16:47:32+09:00",
"updatedAt": "2020-05-30T16:47:32+09:00",
"deletedAt": null,
"userName": "user4",
"companyId": 3,
"company": {
"id": 3,
"createdAt": "2020-05-30T16:47:29+09:00",
"updatedAt": "2020-05-30T16:47:29+09:00",
"deletedAt": null,
"companyName": "B株式会社"
},
"language": [
{
"id": 1,
"createdAt": "2020-05-30T16:47:29+09:00",
"updatedAt": "2020-05-30T16:47:29+09:00",
"deletedAt": null,
"languageName": "日本語"
},
{
"id": 2,
"createdAt": "2020-05-30T16:47:29+09:00",
"updatedAt": "2020-05-30T16:47:29+09:00",
"deletedAt": null,
"languageName": "英語"
},
{
"id": 3,
"createdAt": "2020-05-30T16:47:29+09:00",
"updatedAt": "2020-05-30T16:47:29+09:00",
"deletedAt": null,
"languageName": "フランス語"
}
]
},
{
"id": 5,
"createdAt": "2020-05-30T16:47:32+09:00",
"updatedAt": "2020-05-30T16:47:32+09:00",
"deletedAt": null,
"userName": "user5",
"companyId": 4,
"company": {
"id": 4,
"createdAt": "2020-05-30T16:47:29+09:00",
"updatedAt": "2020-05-30T16:47:29+09:00",
"deletedAt": null,
"companyName": "D株式会社"
},
"language": [
{
"id": 4,
"createdAt": "2020-05-30T16:47:29+09:00",
"updatedAt": "2020-05-30T16:47:29+09:00",
"deletedAt": null,
"languageName": "イタリア語"
}
]
}
]
SELECT * FROM `users` WHERE `users`.`deleted_at` IS NULL[] 5
SELECT * FROM `companies` WHERE `companies`.`deleted_at` IS NULL AND ((`id` IN (?,?,?,?,?)))[0xc000306d10 0xc000306d88 0xc000306e00 0xc000306e78 0xc000306ef0] 4
SELECT * FROM `languages` INNER JOIN `user_languages` ON `user_languages`.`language_id` = `languages`.`id` WHERE `languages`.`deleted_at` IS NULL AND ((`user_languages`.`user_id` IN (?,?,?,?,?)))[1 2 3 4 5] 0
では、こんな場合はどうでしょう。
【お題】
たしかに、基本は全ての関連モデルのデータを取得したいものの、一部の関連モデルのデータは取得しないようにしたい。
そんなときに使用するのが、gorm:"PRELOAD:false"
です。
試しに、先ほど使用したUserモデルのCompanyを以下のように変更してみます。
type User struct {
Model
UserName *string `gorm:"" json:"userName"` // ユーザー名
CompanyID *int `gorm:"" json:"companyId"` // 所属企業ID
Company *Company `gorm:"PRELOAD:false" json:"company"`
Languages []*Language `gorm:"many2many:user_languages;association_autoupdate:false" json:"language"` // 使用可能言語
}
すると、以下の通り、Set("gorm:auto_preload", true)
をつけているにも関わらず、companyの項目はnullになり、Preloadingの対象から除外されていることがわかります。
[
{
"id": 1,
"createdAt": "2020-05-30T16:47:31+09:00",
"updatedAt": "2020-05-30T16:47:31+09:00",
"deletedAt": null,
"userName": "user1",
"companyId": 1,
"company": null,
"language": [
{
"id": 1,
"createdAt": "2020-05-30T16:47:29+09:00",
"updatedAt": "2020-05-30T16:47:29+09:00",
"deletedAt": null,
"languageName": "日本語"
}
]
},
{
"id": 2,
"createdAt": "2020-05-30T16:47:32+09:00",
"updatedAt": "2020-05-30T16:47:32+09:00",
"deletedAt": null,
"userName": "user2",
"companyId": 1,
"company": null,
"language": [
{
"id": 2,
"createdAt": "2020-05-30T16:47:29+09:00",
"updatedAt": "2020-05-30T16:47:29+09:00",
"deletedAt": null,
"languageName": "英語"
},
{
"id": 4,
"createdAt": "2020-05-30T16:47:29+09:00",
"updatedAt": "2020-05-30T16:47:29+09:00",
"deletedAt": null,
"languageName": "イタリア語"
}
]
},
{
"id": 3,
"createdAt": "2020-05-30T16:47:32+09:00",
"updatedAt": "2020-05-30T16:47:32+09:00",
"deletedAt": null,
"userName": "user3",
"companyId": 2,
"company": null,
"language": [
{
"id": 2,
"createdAt": "2020-05-30T16:47:29+09:00",
"updatedAt": "2020-05-30T16:47:29+09:00",
"deletedAt": null,
"languageName": "英語"
}
]
},
{
"id": 4,
"createdAt": "2020-05-30T16:47:32+09:00",
"updatedAt": "2020-05-30T16:47:32+09:00",
"deletedAt": null,
"userName": "user4",
"companyId": 3,
"company": null,
"language": [
{
"id": 1,
"createdAt": "2020-05-30T16:47:29+09:00",
"updatedAt": "2020-05-30T16:47:29+09:00",
"deletedAt": null,
"languageName": "日本語"
},
{
"id": 2,
"createdAt": "2020-05-30T16:47:29+09:00",
"updatedAt": "2020-05-30T16:47:29+09:00",
"deletedAt": null,
"languageName": "英語"
},
{
"id": 3,
"createdAt": "2020-05-30T16:47:29+09:00",
"updatedAt": "2020-05-30T16:47:29+09:00",
"deletedAt": null,
"languageName": "フランス語"
}
]
},
{
"id": 5,
"createdAt": "2020-05-30T16:47:32+09:00",
"updatedAt": "2020-05-30T16:47:32+09:00",
"deletedAt": null,
"userName": "user5",
"companyId": 4,
"company": null,
"language": [
{
"id": 4,
"createdAt": "2020-05-30T16:47:29+09:00",
"updatedAt": "2020-05-30T16:47:29+09:00",
"deletedAt": null,
"languageName": "イタリア語"
}
]
}
]
SELECT * FROM `users` WHERE `users`.`deleted_at` IS NULL[] 5
SELECT * FROM `languages` INNER JOIN `user_languages` ON `user_languages`.`language_id` = `languages`.`id` WHERE `languages`.`deleted_at` IS NULL AND ((`user_languages`.`user_id` IN (?,?,?,?,?)))[4 5 1 2 3] 0
##Nested Preloading
先ほどの3つのモデルに加えて、Departmentモデルを作成し、Company(企業)とDepartment(部署)が多対多(Many2Many)の関係になるよう以下のようなアソシエーションを組みます。
type User struct {
Model
UserName *string `gorm:"" json:"userName"` // ユーザー名
CompanyID *int `gorm:"" json:"companyId"` // 所属企業ID
Company *Company `gorm:"" json:"company"`
Languages []*Language `gorm:"many2many:user_languages;association_autoupdate:false" json:"language"` // 使用可能言語
}
type Language struct {
Model
LanguageName *string `gorm:"" json:"languageName"`
}
type Company struct {
Model
ConmpanyName *string `gorm:"" json:"companyName"`
Departments []*Department `gorm:"many2many:company_departments; association_autoupdate:false" json:"department"`
}
type Department struct {
Model
DepartmentName *string `gorm:"" json:"departmentName"`
}
このとき、UserモデルからDepartmentモデルのデータをPreloadingするにはどのようにすればよいでしょうか。
それぞれのモデルの関係性を考えると、Companyは直接Userモデルとのアソシエーションを結んでいますが、DepartmentはCompanyによってネストされており、Userとの直接のアソシエーションはありません。
そこで、以下のように「.(ドット)」でPreload()
の中のstructをつなげることで、ネストされたモデルのデータをPreloadingすることができます。
func GetAllUsers(limit int64, offset int64) (ml []*User, err error) {
tx := db.Preload("Company.Departments").Begin()
err = tx.Find(&ml).Commit().Error
return ml, err
}
[
{
"id": 1,
"createdAt": "2020-05-30T17:28:40+09:00",
"updatedAt": "2020-05-30T17:28:40+09:00",
"deletedAt": null,
"userName": "user1",
"companyId": 1,
"company": {
"id": 1,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"companyName": "A株式会社",
"department": [
{
"id": 1,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"departmentName": "営業部"
},
{
"id": 2,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"departmentName": "マーケティング部"
},
{
"id": 3,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"departmentName": "情報システム部"
},
{
"id": 4,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"departmentName": "経理部"
}
]
},
"language": null
},
{
"id": 2,
"createdAt": "2020-05-30T17:28:40+09:00",
"updatedAt": "2020-05-30T17:28:40+09:00",
"deletedAt": null,
"userName": "user2",
"companyId": 1,
"company": {
"id": 1,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"companyName": "A株式会社",
"department": [
{
"id": 1,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"departmentName": "営業部"
},
{
"id": 2,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"departmentName": "マーケティング部"
},
{
"id": 3,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"departmentName": "情報システム部"
},
{
"id": 4,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"departmentName": "経理部"
}
]
},
"language": null
},
{
"id": 3,
"createdAt": "2020-05-30T17:28:40+09:00",
"updatedAt": "2020-05-30T17:28:40+09:00",
"deletedAt": null,
"userName": "user3",
"companyId": 2,
"company": {
"id": 2,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"companyName": "C株式会社",
"department": [
{
"id": 1,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"departmentName": "営業部"
},
{
"id": 2,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"departmentName": "マーケティング部"
},
{
"id": 4,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"departmentName": "経理部"
}
]
},
"language": null
},
{
"id": 4,
"createdAt": "2020-05-30T17:28:40+09:00",
"updatedAt": "2020-05-30T17:28:40+09:00",
"deletedAt": null,
"userName": "user4",
"companyId": 3,
"company": {
"id": 3,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"companyName": "B株式会社",
"department": [
{
"id": 1,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"departmentName": "営業部"
},
{
"id": 3,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"departmentName": "情報システム部"
},
{
"id": 4,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"departmentName": "経理部"
}
]
},
"language": null
},
{
"id": 5,
"createdAt": "2020-05-30T17:28:40+09:00",
"updatedAt": "2020-05-30T17:28:40+09:00",
"deletedAt": null,
"userName": "user5",
"companyId": 4,
"company": {
"id": 4,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"companyName": "D株式会社",
"department": [
{
"id": 1,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"departmentName": "営業部"
},
{
"id": 2,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"departmentName": "マーケティング部"
},
{
"id": 3,
"createdAt": "2020-05-30T17:28:38+09:00",
"updatedAt": "2020-05-30T17:28:38+09:00",
"deletedAt": null,
"departmentName": "情報システム部"
}
]
},
"language": null
}
]
SELECT * FROM `users` WHERE `users`.`deleted_at` IS NULL[] 5
SELECT * FROM `companies` WHERE `companies`.`deleted_at` IS NULL AND ((`id` IN (?,?,?,?,?)))[0xc00030f330 0xc00030f3a8 0xc00030f420 0xc00030f498 0xc00030f510] 4
SELECT * FROM `departments` INNER JOIN `company_departments` ON `company_departments`.`department_id` = `departments`.`id` WHERE `departments`.`deleted_at` IS NULL AND ((`company_departments`.`company_id` IN (?,?,?,?)))[1 2 3 4] 0
なお、前述のSet("gorm:auto_preload", true)
を設定している場合は、ネストされたモデルのデータも自動で取得することができます。
ただし、Set("gorm:auto_preload", true)
を濫用してしまうと、本来は不要なデータも毎回Preloadingしてしまいパフォーマンスが低下してしまう可能性がありますし、アソシエーションが複雑になってくると予期しないエラー(無限ループなど)が発生してしまう可能性がありますので、Preload()
でPreloadingする先を指定できる場合は、なるべくきちんと指定しましょう。