Laravelにおいて1対1・1対多リレーションを定義する方法と、定義したリレーションを用いてデータを取り出す方法を解説します。
筆者自身かなり躓いたので、自身の復習も兼ねて筆者が理解した範囲でまとめています。
なお1対1と1対多は扱いがかなり似ているので、1対多メインで解説しながら異なる箇所のみ「1対1」の説明を入れていきます。
1対1についてはこのメモマークで補足説明します。
1対多のイメージ・ER図
説明していくにあたって、とあるフリマサイトを想定します。
商品の情報(名前など)がItemsテーブルに入っており、商品の状態(とても良い・良い・悪い・とても悪い)を表すデータがConditionsテーブルに入っています。
Itemsテーブルに外部キーとしてCondition_idが存在し、ItemsテーブルとConditionsテーブルをつないでいます。
id | name(状態) |
---|---|
1 | とても良い(傷なし・美品) |
2 | 良い(傷なし) |
3 | 悪い(傷あり) |
4 | とても悪い(大きな傷あり) |
id | condition_id | name(商品名) |
---|---|---|
1 | 2(良い) | 靴 |
2 | 1(とても良い) | シャツ |
3 | 1(とても良い) | スーツ |
4 | 4(とても悪い) | ハンカチ |
ここで、2番目の表「Itemsテーブルのイメージ」を見ると、Condition_idに同じ数字(シャツとスーツがともに1:とても良いになっている)が入っています。このように、Condition1つに対して複数のItemが結びつくことができるので、ConditionとItemは1対多の関係になります。
ここでCondition_idに同じ数字が入らないような場合、Conditionとitemは1対1の関係になるイメージです。
ER図にするとこんな感じ。PKは主キー、FKは外部キーです。

1対1の場合、両テーブルともConditionsテーブルについているような縦線2本になります。
主と従(親と子)
リレーションには主従(親子)関係があります。
- 主(親):外部キーがない側(Conditionsテーブル)
- 従(子):外部キーがある側(Itemsテーブル)
余談ですが筆者はここで混乱しました。というのも、Itemsテーブルのほうが様々な情報が入っており、「こちらが主じゃないの?」と思ってしまったからです。
分からなくなってしまう場合は単純に外部キーの有無で覚えるのがいいと思います。
コードの記述
ここからは実際にコードを書いていきます。
モデルへの記述
主テーブルのモデル(Condition.php)
まずは主テーブルのモデル(Condition.php)への記述。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Condition extends Model
{
use HasFactory;
protected $fillable = [
'name'
];
public function item()
{
return $this->hasMany(Item::class);
}
}
この部分がリレーションに必要な記述です。
public function item()
{
return $this->hasMany(Item::class);
}
1対多の場合は「hasMany」を用います。hasMany(Item::class)の「Item」は従テーブルのモデル名です。
public function item() の「item」は何でも良いですが、従テーブルのモデル名と同じにしておくのが無難そうです(データを取り出すときにこれを使います)。
1対1の場合は「hasMany」の代わりに「hasOne」を使います。あとは同じです。
従テーブルのモデル(Item.php)
続いて従テーブルのモデル(Item.php)への記述。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Item extends Model
{
use HasFactory;
protected $fillable = [
'name',
];
public function condition()
{
return $this->belongsTo(Condition::class);
}
}
この部分がリレーションに必要な記述です。
public function condition()
{
return $this->belongsTo(Condition::class);
}
こちらは「belongsTo」を用います。belongsTo(Condition::class)の「Condition」部分は主テーブルのモデル名を記述します。
こちらは1対1の場合も同じく「belongsTo」です。
リレーションに必要な記述はたったこれだけ。これで2つのテーブルが結びつきました。
データの取り出し
続いてデータの取り出しに移ります。
今回は、下の表でid=1の靴の状態、すなわち「良い」という言葉を取り出していきたいと思います。
id | condition_id | name(商品名) |
---|---|---|
1 | 2(良い) | 靴 |
2 | 1(とても良い) | シャツ |
3 | 1(とても良い) | スーツ |
4 | 4(とても悪い) | ハンカチ |
コントローラへの記述
public function view()
{
$condition = Item::find(1)->condition->name;
return view('/', compact('condition'));
}
「Item::find(1)」でItemテーブルからid=1(靴)のデータすべてを取り出し、続いて「->condition」(モデルに記述したメソッド名、public function condition() の「condition」部分)で靴のConditionデータ(id=2, name=良い)を取り出し、さらにそこから「->name」で必要なデータ(name=良い)のみを取り出しています。
ビューファイルへの記述
あとはビューファイルの「良い」という文字を表示させたい箇所で以下の記述をすればOKです。
{{ $condition }}
まとめ
以上、1対1・1対多リレーションの記述方法でした。概要をまとめます。
- 主と従:外部キーがない=主、外部キーがある=従
- 主テーブルのモデル:1対1ならhasOne、1対多ならhasMany
- 従テーブルのモデル:belongsTo
以外に単純だと感じた方も多いのではないかと思います。参考にしていただければ幸いです。
読んでくださってありがとうございました。
コメント