Laravel – リレーション

 

概要

Laravelでは、テーブル間のリレーションを設定することで、外部キーで関連付けられた複数のモデルを(外部キーを意識することなく)一貫して扱うことができる。

リレーションの種類と定義方法

リレーションはモデル定義で設定し、以下の3種類の何れかを設定する。

hasOne
1対1のリレーションの親のモデルで設定し、親データに属する子データのモデルとidを指定する。これにより親データから子データやそのプロパティーの参照が可能になる。
hasMany
1対nの親のモデルで設定し、親データに属する子データのモデルとidを指定する。これにより親データから子データのコレクション、要素インスタンスやそのプロパティーの参照が可能になる。
belongsTo
1対1、1対nとも子のモデルで設定し、子データが属する親データを指す外部キーと親のモデルを指定する。これにより子データから親データやそのプロパティーが参照可能になる。

いずれについてもモデルでの記述方法は同じで、たとえばhasManyを例にとると以下の様に書く。

子の参照名はモデル名のスモールケースで、hasOneの場合は単数形、hasManyの場合は複数形。

例えば親テーブルcustomersのデータが子テーブルemailsのデータを1つだけ持つ場合は以下の様に書く。

また、親テーブルcustomersのデータが子テーブルordersの複数のデータを持つ場合は以下の様に書く。

子テーブルのデータが親テーブルのデータに属することを設定するbelongsToでは、メソッド名は単数形。

リレーション設定後の参照方法

リレーションを設定すると、そのメソッド名と同じ名前のプロパティーによって親から子、子から親のモデルインスタンスを参照できるようになる。

先のCustomerEmailOrderの場合、以下の様に参照する。

子データが得られれば、以下の例の様にそのプロパティーも得ることができる。

挙動確認

準備

設定

挙動確認のため、3つのモデルとテーブルを作成する。

  • Customer
    • Auto Increment(AI)のid、顧客名、作成・更新日時を持つ
    • e-mailアドレスを1つだけ持つ
    • 複数の注文を持つ
  • Email
    • AIのid、e-mailアドレスを持つ顧客のid、アドレス、作成・更新日時を持つ
  • Order
    • AIのid、注文した顧客のid、注文品、作成・更新日時を持つ

モデル作成

artisanでCustomerEmailOrderの3つのモデルを、マイグレーションファイルとともに作成する。

timestampsの生成の抑制

本筋ではないが、ここではテーブル構造をシンプルにするため、デフォルトのtimestampsの生成を抑制している。

マイグレーションファイル編集

マイグレーションファイルを編集し、各テーブルの要素を追加する。なおタイムスタンプを省略するため、各マイグレーションファイルに自動で記述される$table->timestamps()は削除している。

customersテーブルには顧客名を追加記述する。

emailsテーブルには以下を追加記述する。

  • 親のcustomersテーブルのidを参照する外部キーcustomer_idと、メールアドレスemail
  • customer_id外部キー設定

ordersには以下を追加記述する。

  • 親のcustomersテーブルのidを参照する外部キーcustomer_idと、注文品名item
  • customer_id外部キー設定

マイグレーション

マイグレーションを実行する。

テーブル構造

生成された3つのテーブルは以下のとおり。

customersテーブル

emailsテーブル。

ordersテーブル。

リレーション設定

リレーションを各モデルで設定する。なおタイムスタンプを省略するため、各モデルで$timestampsfalseにセットする行を追加している。

Customerモデルでは、1対1でEmailを子に持つこと、1対nでOrderを子に持つことを設定。

EmailモデルではCustomerを親に持つことを設定。

OrderモデルではCustomerを親に持つことを設定。

テストデータ作成

tinkerでテストデータを作成し、データベースに登録する。

Customer

まずCustomerのデータを登録する。

3人の顧客データを登録。

Email

Emailのデータを、Customerの各データに関連付けながら登録する。ここではcustomer1customer2に紐づくデータを登録し、customer3のアドレスは未登録とする。

登録後のテーブルは以下のとおり。

Order

Orderのデータを、Customerの各データに関連付けながら登録する。ここではcustomer1に1つの、customer2に2つの注文があり、customer3からの注文はない状態とする。

登録後のテーブルは以下のとおりで、customer1はネジのオーダー1つ、customer2はゴムシートとプラスチック板で2つのオーダー。

リレーションを使った操作

親データを取得

まず3人の顧客のデータを取得する。

親からhasOneを取得

それぞれの顧客データから、hasOneで関連付けられたemailのインスタンスを取得する。$customer3emailは未登録なのでnullとなる。

親からhasManyを取得

それぞれの顧客データから、hasManyで関連付けられたorderのデータを取得する。

  • hasManyリレーションのデータは配列で得られる
  • データが1つの場合は要素数1の配列
  • 子データがない場合は空の配列

hasManyの場合、子データは配列で得られるので、要素指定やforeachなどで個々のデータを取り出す。

子データのプロパティーの取得

hasOnehasManyの子データが親データから得られれば、そのプロパティーを得ることもできる。

hasOneの子から親を取得

hasOneEmailが属するCustomerを取得する例。ここでは変数を介さず、生成したインスタンスから直接プロパティーを参照している。

hasManyの子から親を取得

hasManyで関連付けられた子のOrderから親のCustomerを取得する例。

親データのプロパティーの取得

子データから親データが得られれば、そのプロパティーも得ることができる。

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です