4
4

More than 1 year has passed since last update.

Laravelの外部キー制約を指定する際に使用するconstrained()に任意の指定したidを付与する方法

Last updated at Posted at 2023-01-04

公式の書き方を参照すると、外部キー制約を追加する際、マイグレーションファイルに下記を記述する

マイグレーショファイル
# userテーブルと紐付ける条件で作成した
Schema::create('posts', function (Blueprint $table) {
    $table->id('post_id');
    
    $table->foreignId('user_id')->constrained('users')->onDelete('cascade');
    # または
    $table->foreignId('user_id')->constrained()->onDelete('cascade');
    
    $table->timestamps();
});
  • 今回は、CASCADEの設定も行っている
  • 著者は、userテーブルを題材として使用し、今回の説明を行う

上記の記述の場合、userテーブルが下記の状態であれば、マイグレーションを正常に行う事ができる

id name emeil
1 test1 aaa@example.com
2 test2 aaa@aaa.com

しかし、下記のテーブル構造だった場合、上記の外部キー制約の書き方では、マイグレーションが正常に動作しない
(マイグレーションを実行するとエラーとなる)

user_id name emeil
1 test1 aaa@example.com
2 test2 aaa@aaa.com

エラー文は、下記が表示される

Illuminate\Database\QueryException 

SQLSTATE[HY000]: General error: 1824 Failed to open the referenced table 'user_id' (SQL: alter table `posts` add constraint `posts_user_id_foreign` foreign key (`user_id`) references `user_id` (`id`) on delete cascade)

  at vendor/laravel/framework/src/Illuminate/Database/Connection.php:760
    756▕         // If an exception occurs when attempting to run a query, we'll format the error
    757▕         // message to include the bindings with SQL, which will make this exception a
    758▕         // lot more helpful to the developer instead of just the database's errors.
    759▕         catch (Exception $e) {
  ➜ 760▕             throw new QueryException(
    761▕                 $query, $this->prepareBindings($bindings), $e
    762▕             );
    763▕         }
    764▕     }

      +9 vendor frames 
  10  database/migrations/2023_01_04_231333_create_posts_table.php:22
      Illuminate\Support\Facades\Facade::__callStatic("create")

      +36 vendor frames 
  47  artisan:37
      Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))

DBにアクセスして、エラーで表示されているSQL文を修正し、修正したクエリーを叩けば正常にDBを動かす事ができるが、それではマイグレーションファイルを使う意味がなくなってしまう。また、実際の業務での開発を想定した場合、マイグレーションが正常に動作しないのは、明らかに他の人の迷惑にも繋がる。

DBに接続して直接SQL文を打って修正を試みた為、その内容も記述する
/* エラーで出力されたSQL文 */
alter table `posts` 
add constraint `posts_user_id_foreign` 
foreign key (`user_id`) references `user_id` (`id`) on delete cascade

/* エラー文で出力されたSQLを修正したSQL文 */
alter table `posts` 
add constraint `posts_user_id_foreign` 
foreign key (`user_id`) references `user_id` (`user_id`) on delete cascade

SQL文を見ると references() に任意で指定したid名が入力できれば、正常に動作する事が分かる。
しかし、マイグレーションファイルに正常に動作するSQLを記述する方法が、公式ドキュメントを確認しても記述されていなかった。
ここで、各メソッドの裏側の処理を確認した際、constrained()の裏側の処理にヒントがあった。

constrained()の処理
/**
     * Create a foreign key constraint on this column referencing the "id" column of the conventionally related table.
     *
     * @param  string|null  $table
     * @param  string  $column
     * @return \Illuminate\Database\Schema\ForeignKeyDefinition
     */
    public function constrained($table = null, $column = 'id')
    {
        return $this->references($column)->on($table ?? Str::of($this->name)->beforeLast('_'.$column)->plural());
    }

constrained()の第二引数に任意で指定したid名を入力すれば、正常に動作するのではと思い、第二引数にidを記述したら、正常にマイグレーションができるようになりました。
下記が修正したコード

# 修正前
- $table->foreignId('user_id')->constrained('users')->onDelete('cascade');

# 修正後
+ $table->foreignId('user_id')->constrained('users', 'user_id')->onDelete('cascade');

同じ問題で困っている人がいましたら、是非参考にしてみて下さい。

参考資料

4
4
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
4
4