3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【誰でもわかる】Laravel6.0リレーション入門

Last updated at Posted at 2021-04-17

はじめに

データベースを触り始めると確実に一度は躓きますよね。。
私も最近までデータベース設計がちんぷんかんぷんでした。
少しずつ理解出来てきたので今回は備忘録としてまとめつつ、初心者の方の助けになればと思いまとめてみました。

Laravel6.0の実装でお困り中の方は下記も見てみて下さい。
初歩的なことは下記でできるようになるかと思います。

1対1, 1対多, 多対多ってなんやねん

まずは誰もが思うであろう、こちらから解説します。

1対1

まずこれはほとんど使わないので覚える必要はありません。
双方のレコードが1対1になるもしくは双方のPKが同じケースとなります。

例えるならば、
ユーザーとマイナンバーとかでしょうか。
1人のユーザーに対して1つのマイナンバーが割り振られます。

こうなるとまず思うのが、テーブル分ける必要ってある?という疑問です。
わざわざ分けるメリットもなく普通に同一テーブル内に入れろやということでほぼ使いません。

既存のテーブル構成を変えずに項目を追加したいときは採用するかも・・・

1対多

ここからはよく使うので具体的なLaravelのコードも書いていきます。

Aテーブルのレコードは、Bテーブルの複数レコードと関連するが、
BテーブルのレコードはAテーブルのレコードの1つのみ関連するケースを指します。

例えるならば、
ユーザーと投稿でしょうか。
Twitterなどでも1人のユーザーが複数の投稿を行います。
スクリーンショット 2021-04-16 20.55.20.png

これは国語力を活かして考えるとおすすめです。
上記の例で言うと、
1人のユーザーが複数の投稿を行う → 日本語として正しい
1つの投稿が複数のユーザーで〜〜 → おかしい

ということでこれは、ユーザーテーブルが親で、投稿テーブルが子となります。

他の例としては、顧客と注文で考えてみましょう。
1人の顧客が複数の注文をする → 日本語として正しい
1つの注文が複数の顧客で〜〜 → おかしい

このように考えてみるとわかりやすいのではないでしょうか??

Laravelコード解説

新たにマイグレーションファイルとモデルを作成する

ターミナル
php artisan make:model Models/Post --migration
Migration

database/migrations/XXXX_XX_XX_XXXXXX_create_users_table.php
public function up()
    {
        Schema::create('registers', function (Blueprint $table) {
            // 符号なしBIGINTを使用した自動増分ID
            $table->bigIncrements('id')->comment('id');
            // 20文字以内の文字列
            $table->string('name', 20)->comment('名前');
            // 255文字以内で独自の文字列
            $table->string('email', 255)->unique('email')->comment('メールアドレス');
            // 時間
            $table->timestamps();
        });
    }

database/migrations/XXXX_XX_XX_XXXXXX_create_posts_table.php
public function up()
    {
        Schema::create('registers', function (Blueprint $table) {
            // 符号なしBIGINTを使用した自動増分ID
            $table->bigIncrements('id')->comment('id');
            // 255文字以内の文字列
            $table->string('body', 255)->comment('本文');
            // 1対多リレーション(整数しか入らないのでunsignedBigIntegerを使用)
            $table->unsignedBigInteger('user_id')->comment('ユーザーID');
            // 時間
            $table->timestamps();

            // 外部キー制約
            $table->foreign("user_id")->references("id")->on("users");
        });
    }

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

ターミナル
php artisan migrate
Model

親にhasMany、子にbelongsToを使います。

app/Http/Models/User.php
class User extends Authenticatable
{
    public function posts() {
        return $this->hasMany("App\Models\Post");
    }
}

app/Http/Models/Post.php
class Post extends Model
{
    public function user() {
        return $this->belongsTo("App\Models\User");
    }
}
Controller

コントローラーでのアクセス方法についてです。

app/Http/Controllers/XXXX.php
// model読み込み
use App\Models\User;
use App\Models\Post;

public function index() {
    // 親から子
    // ユーザーのIDが1の投稿すべて
    User::find(1)->posts;

    // 子から親
    // 投稿のIDが1のユーザーの名前
    Post::find(1)->user->name;

    // 子から親
    // 投稿すべてを取得
    // viewファイルで親にアクセスする際は、{{ $post->user->name }}でuserのnameが取得可能です
    Post::all();

    // よりスマートなのはwithを使いましょう。(親から子)
    User::with("posts");
}

多対多

AテーブルのレコードもBテーブルのレコードも、
双方の複数レコードと関連するケースを指します。

例えるならば、
投稿と投稿のカテゴリでしょうか。
1つの投稿に複数のカテゴリーがあり、
1つのカテゴリーに複数の投稿があります。

スクリーンショット 2021-04-17 13.20.06.png

これも国語力を活かして考えるとおすすめです。
1対多の場合は入れ替えると片方は意味が通じて、もう一方は日本語として正しくない形となりました。
今回は多対多は入れ替えてもどちらとも日本語として正しくなります。

上記の例で言うと、
1つの投稿に複数のカテゴリーがあります → 日本語として正しい
1つのカテゴリーに複数の投稿があります → 日本語として正しい

私のこのqiitaの記事は合計9つのタグが紐づいています。スクリーンショット 2021-04-17 13.23.54.png

1つの投稿に複数のカテゴリーが紐付き、
このLaravelのタグは私以外の様々な方がこちらのタグを紐づけています。

このように考えていくと理解しやすいのではないでしょうか?
では、Laravelのコード解説に移ります。

Laravelコード解説

多対多の場合は中間テーブルというものを使って構築していきます。
なぜ中間テーブルを使うのかは図解などがあった方がわかりやすいのですが自分に作成するスキルがないので割愛しますw
しかし他の方の説明で素晴らしいものがあったので中間テーブルを詳しく知りたい方はこちらをご確認ください。

新たにマイグレーションファイルとモデルを作成しましょう。
今回のケースは、
親がPostとCategoryとなり、子がpost_categoryです。

ターミナル
// カテゴリー
php artisan make:model Models/Category --migration

// 中間テーブルのマイグレーションファイル
php artisan make:migration create_posts_categories_table
Migration

database/migrations/XXXX_XX_XX_XXXXXX_create_categories_table.php
public function up()
    {
        Schema::create('registers', function (Blueprint $table) {
            // 符号なしBIGINTを使用した自動増分ID
            $table->bigIncrements('id')->comment('id');
            // 20文字以内の文字列
            $table->string('category', 20)->comment('カテゴリー');
            // 時間
            $table->timestamps();
        });
    }
database/migrations/XXXX_XX_XX_XXXXXX_create_posts_table.php
public function up()
    {
        Schema::create('registers', function (Blueprint $table) {
            // 符号なしBIGINTを使用した自動増分ID
            $table->bigIncrements('id')->comment('id');
            // 255文字以内の文字列
            $table->string('body', 255)->comment('本文');
            // 1対多リレーション(整数しか入らないのでunsignedBigIntegerを使用)
            $table->unsignedBigInteger('user_id')->comment('ユーザーID');
            // 時間
            $table->timestamps();

            // 外部キー制約
            $table->foreign("user_id")->references("id")->on("users");
        });
    }

database/migrations/XXXX_XX_XX_XXXXXX_create_posts_categories_table.php
public function up()
    {
        Schema::create('posts_categories', function (Blueprint $table) {
            $table->unsignedBigInteger('post_id')->comment('投稿ID');
            $table->unsignedBigInteger('category_id')->comment('カテゴリーID');
            // プライマリーキー制約(PK)
            $table->primary(["post_id", "category_id"]);
        });
    }

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

ターミナル
php artisan migrate
Model

親にhasMany、子にbelongsToを使います。

app/Http/Models/Post.php
class Post extends Model
{
    public function user() {
        return $this->belongsTo("App\Models\User");
    }
    // belongsToMany('関係するモデル', '中間テーブルのテーブル名', '中間テーブル内で対応しているID名', '関係するモデルで対応しているID名');
    public function categories() {
        return $this->belongsToMany("App\Models\Category", "posts_categories", "post_id", "category_id");
    }
}
app/Http/Models/Category.php
class Post extends Model
{
    // belongsToMany('関係するモデル', '中間テーブルのテーブル名', '中間テーブル内で対応しているID名', '関係するモデルで対応しているID名');
    public function posts() {
        return $this->belongsToMany("App\Models\Post", "posts_categories", "category_id", "post_id");
    }
}

モデルファイルは必要ありません。

Controller

コントローラーでのアクセス方法についてです。

app/Http/Controllers/XXXX.php
// model読み込み
use App\Models\Post;
use App\Models\Category;

public function index() {
    // 親から親
    // 投稿のIDが1のカテゴリーすべて
    Post::find(1)->categories;

    // 親から親
    // 投稿のIDが1のカテゴリー名
    Post::find(1)->categories->category;
}

3
5
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
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?