多対多の関係性
多対多の関係性では、これまでとは少し違うことが必要になります。今までは、外部キーに関連するデータのidを設定していました。1対1や1対多では、登録すべきキーが一つだったため問題ありませんが、多対多では問題が発生します。なぜなら、必要な外部キーが複数あり、データベースのカラムは一つのカラムにつき一つの値しか保存できないため、今までの方法は利用できません。そこで、中間テーブルを用いてこの問題を解決します。
中間テーブル
中間テーブルとは、多対多のリレーションシップを表現するために使用される特別なテーブルです。それぞれのテーブルの主キーを組み合わせたデータを保存します。例えば以下のようなテーブルが考えられます。
user_id | course_id |
1 | 1 |
1 | 2 |
2 | 1 |
2 | 2 |
このテーブルでは、usersテーブルとcoursesテーブルのidの関係性を示しています。ユーザーを講座を受けるユーザー、コースを講座と考えると、ユーザー1はコース1とコース2を受けており、ユーザー2もコース1とコース2を受けています。コース側から見ると、コース1コース2ともに、ユーザー1とユーザー2が受講者であることがわかります。
このように中間テーブルを使用することで多対多の関係性を表現することができます。
多対多の関係性の設定方法
今回は多対多の関係性を設定します。ここでは、UserモデルとCourseモデルを使用し、ユーザーが複数のコースを受講し、コースも複数の受講者がいることの関係性を設定します。Courseモデルは以下の通りです。
カラム名 | 内容 |
title | コースのタイトル |
マイグレーションファイルは簡単なものになるため、詳しいことは割愛します。
中間テーブルの作成
中間テーブルを作成します。中間テーブルの名前は、「テーブル1(単数形)_テーブル2(単数形)_table」であり、テーブル1とテーブル2はアルファベット順になります。usersテーブルとcourseテーブルの中間テーブルの名前は、「course_user_table」となります。以下のコマンドでマイグレーションファイルを作成します。マイグレーションファイルは以下の通りです。
Schema::create('course_user', function (Blueprint $table) {
$table->id();
$table->foreignId("user_id")->constrained();
$table->foreignId("course_id")->constrained();
$table->timestamps();
});
usersテーブルとcoursesテーブルのidを紐づけるだけのマイグレーションファイルとなります。
モデルに関連性を記述
次に、モデルに関係性を記述します。Userモデル、Courseモデルに以下のようにメソッドを追加します。
Userモデル
public function courses() {
return $this->belongsToMany(Course::class);
}
Coiurseモデル
public function users () {
return $this->belongsToMany(User::class);
}
belongsToManyメソッドは多対多のリレーションシップを定義するメソッドです。
関係性のテスト
tinkerを使用して関係性をテストします。以下のコードでダミーデータを生成し各データの関係性を設定します。
use App\Models\User;
use App\Models\Course;
#ダミーユーザー1、2
$user1 = new User();
$user1->name = "test1";
$user1->email = "test1@example.com";
$user1->password = Hash::make("password");
$user1->is_admin = false;
$user1->save();
$user2 = new User();
$user2->name = "test2";
$user2->email = "test2@example.com";
$user2->password = Hash::make("password");
$user2->is_admin = false;
$user2->save();
#ダミーコース1、2
$course1 = new Course();
$course1->title = "test course 1";
$course1->save();
$course2 = new Course();
$course2->title = "test course 2";
$course2->save();
#ユーザーとコースの紐づけ
$user1->courses()->attach([1,2]);
$user2->courses()->attach([1,2]);
Userモデルのcoursesメソッドにあるattachメソッドでデータの紐づけを行います。紐づけしたいコースのidをattachメソッドに引き渡します。
次に、データベースの関係性が設定できているかどうか確認します。以下のコマンドで、user1、user2から紐づけたコースのデータが、course1、course2から紐づけたユーザーのデータが取得できるか確認します。また、紐づけたデータすべてが取得できるか確認します。
$user1->courses;
$user2->courses;
$course1->users;
$course2->users;
上記のコマンドで、コース、ユーザーの情報が取得できれば成功です。
ここまでで、データベースのリレーションシップについて解説してきました。リレーションシップを使用することでデータベースのさらなる利用ができるようになると思います。