LoginSignup
44
27

More than 3 years have passed since last update.

Goでよく使われるgormを理解する:Preloading編

Last updated at Posted at 2020-05-30

目次

はじめに
はじめに

CRUD Interface
Goでよく使われるgormを理解する:Query編

Associations
Goでよく使われるgormを理解する:Associations編
Goでよく使われるgormを理解する:Preloading編

Preloading (Eager loading)

Preloadingは事前読み込みのことです。多くのormで実装されている機能ですが、gormでもPreload(struct's)を指定することで、リソースを先読みしてキャッシュできるようなります。

Preload

Preloadを使わない場合

まずは、以下のようなstructを定義します。

activity_plans

type ActivityPlan struct {
    Model
    ActivityPlanName *string `gorm:"" json:"activityPlanName"`
    Activities []*Activity `gorm:"many2many:activity_plan_activities" json:"activity"`
}
activities

type Activity struct {
    Model
    ActivityName *string `gorm:"" json:"activityName"`
}

そして、DBからデータを取得するためのfunctionをActivityPlanモデルに作成し、まずはPreloadなしで実行してみます。

ActivityPlanのfunction
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側に設定を追加します。

Userの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することができます。

Userのfunction
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する先を指定できる場合は、なるべくきちんと指定しましょう。

44
27
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
44
27