やること
同じテーブル内でのリレーション?なるものを実装したので備忘録
環境
- Laravel5.8
- Docker
- MySQL 8.0
内部リレーションとは
あるテーブルのあるカラムの親となるカラムが同じテーブルに存在する時のこと。
例としてTwitterのようなアプリで女子高生たちが会話していると考えます。
バカ:今からスゴイこと言ってイイ?
↪️オタ:いいから早く言え
↪️バカ:諦めたらそこで試合終了じゃね?
↪️ロボ:すごいと思う。すでに試合終了してるのにそのセリフに感動できるあたり。
↪️はリプだと考えてください。
この情報を管理するためにはusersテーブルとcommentsテーブルが必要です。そこでそれぞれを以下のように設計します。
usersテーブル
id | name |
---|---|
1 | バカ |
2 | オタ |
3 | ロボ |
commentsテーブル
id | user_id | comment | parent_id |
---|---|---|---|
1 | 1 | 今からスゴイこと言ってイイ? | null |
2 | 2 | いいから早く言え | 1 |
3 | 1 | 諦めたらそこで試合終了じゃね? | 1 |
4 | 3 | すごいと思う。すでに試合終了してるのにそのセリフに感動できるあたり。 | 1 |
どのコメントにコメントをしたのかを表すのがparent_id
です。
リレーションはこんな感じで書きます。
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
protected $guarded = ['id'];
public function parentComment()
{
return $this->hasOne(Comment::class, 'id', 'parent_id');
}
}
parentComment()
は子カラムの親カラムを探す、というメソッドになっていて、第一引数に参照するモデル(テーブル)、第二引数には外部キー、第三引数には子カラムのリレーションキーを書きます。
これでどのコメントにコメントしたかをリレーションで表現できるようになります!
最後に
以前記事にしたClosureTableをEagerloadしたいときに、もし1つ上の親だけを取ってくるならこの方法で呼び出しできるようになります。
ClosureTableを使って〇〇年のアニメを季節ごとに1テーブルで管理する
今回の場合、EagerLoadするなら
Comment::with('comment.parentComment')->get()
でとることができます!
(with使っても複数リレーションするとクエリが亀になってしまうけど。。。)