DB のリレーション

# DB のリレーション

システム開発する上で、DB のリレーションは便利です。
以下は、私が Laravel でシステム開発したときの備忘録です。

## マイグレーション

「Items」テーブルに「Users」の主キー「id」を紐づけしたいと考えました。

![about_db_foreign_key_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525820/68f1322c-da6e-464b-801d-bd88765dcc28.png)

Users テーブルはデフォルトで作られているため、特に変更せず
今回は Items テーブルのマイグレーションから作成していきます。

### `create_items_table`の作成

1.プロジェクトフォルダで、ターミナルを開きます。

```sh
$ cd test // 現在の階層の中のtest(フォルダ)に移動する
```

2.ターミナルで以下のコマンドを叩きます。

```sh
$ php artisan make:migration create_items_table
```

<font color="red">※create\_(作成したいテーブル名)\_table で作成します。</font>
<font color="red">　また、テーブル名は **複数形** 、モデル名は **単数形** を使います。</font>

これにより、`database/migrations/YYYY_mm_dd_XXXXXX_create_items_table.php`が生成されます。
※`YYYY_mm_dd_XXXXXX`には作成した日時が入ります。

### カラムの編集および外部キーの設定

`database/migrations/YYYY_mm_dd_XXXXXX_create_items_table.php`の`up()`を編集します。

```php:database/migrations/YYYY_mm_dd_XXXXXX_create_items_table.php
    public function up()
    {
        Schema::create('items', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->text('text')->nullable();
            $table->bigInteger('user_id');
            $table->timestamps();

            $table->foreign('user_id')->references('id')->on('users');
        });
    }
```

これで外部キーとして渡すことができます。

```php:抜粋
$table->foreign('user_id')->references('id')->on('users');
// $table->foreign(外部キーカラム)->references(主キーカラム)->on(主キーテーブル);
```

しかし、
これだけでは上手くいかないんです。

### `->unsigned()`の追加

実は`->bigIncrements()`で指定されている主キーは自動で`UNSIGNED`が追加されています。
そのため、外部キーでも指定が必要です。

```php:database/migrations/YYYY_mm_dd_XXXXXX_create_items_table.php
            $table->bigInteger('user_id')->unsigned();
```

これで、外部キーが正常に渡せる状態になりました。

## モデルのリレーション

これで DB のリレーション自体は完了しているのですが、
もう少し呼び出しやすくするために、各テーブルのモデル同士でもリレーションを組んでいきます。

### モデルの作成

すでにデフォルトで「User モデル」が存在するため、今回は「Item モデル」を作成します。

```sh
$ php artisan make:model Item
```

これで、`app/Item.php`が生成されます。

### リレーションの設定

さて、リレーションを設定する訳なのですが、
ここで改めて「Users」と「Items」の関係をイメージしてみます。

![about_db_foreign_key_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525820/3f7a7a10-8520-7637-b334-311e53e2f85e.png)

このようなイメージですね。
各 User がいくつかの Item を持っている状態をイメージしています。

ここで大事なのは、

- 何が何を持っているのか
- 1：1？　 1：多？　多：多？

という情報です。

今回でいうと、
「<font color="red">一人の</font>**User**が<font color="red">複数の</font>**Item**を持っている → **1：多**」です。

それぞれリレーションの設定方法が違うので、注意してください。
今回他は割愛し、1：多のみを説明します。
他の情報が欲しい方は[Laravel 公式](https://readouble.com/laravel/6.x/ja/eloquent-relationships.html)を参照してください。

まずは、主体となる「Users」の方から追記します。
以下のコードを追加してください。

```php:app/User.php
class User extends Authenticatable
{

----------(略)----------

+   public function items()
+   {
+       return $this->hasMany('App\Item');
+   }

}
```

次に、「Items」の方です。
呼び出すメソッドが違うため注意してください。

```php:app/Item.php
class Task extends Model
{

+   public function user()
+   {
+       return $this->belongsTo('App\User');
+   }

}
```

これでリレーションが設定できました。

## リレーションを使った呼び出し

最後にこのリレーションを使って呼び出す方法も記載しておきます。

### 「山田太郎」の「item」を取得

```php:「山田太郎」の「item」を取得
use App\User;

$user = User::where("name", "山田太郎");
$items = $user->items()->get();
```

これで山田太郎が持つ「item」を全て取得することができます。

```php:「山田太郎」の「item」を取得
use App\User;

$items = User::where("name", "山田太郎")->items()->get();
```

これも可能です。

### リレーションを設定していない場合

```php:リレーションを設定していない場合
use App\User;
use App\Item;

$user = User::where("name", "山田太郎")->first();
$items = Item::where("user_id", $user->id)->get();
```

両方呼び出す必要が出てきます。

`$user->items()->get()`の方が
**このユーザのアイテムをゲット**と分かりやすいですね。