Jorge Anzola
Jorge Anzola

Reputation: 1235

Cannot add foreign key constraint [Laravel 5.6]

tl;dr. Solution:

Thanks to Jonas.

the problem was that the tables I was referring as foreign, were not InnoDB.

I added raw SQL statements in alter migrations and then added the foreign keys:

DB::statement("ALTER TABLE table ENGINE='InnoDB';");

Original question

First, before the Stackoverflow police bust me, I know this question is probably 83% of the database of this website. But me is special (Kidding, I know I'm not). But I've tried most of the common stuff and nothing seems to work. So probably I'm overseeing something.

Error

General error: 1215 Cannot add foreign key constraint (SQL: alter table applications add constraint applications_user_id_foreign foreign key (user_id) references users (id) on delete cascade)

This is my migration:

public function up()
{
    Schema::create("applications", function(Blueprint $table) {
        $table->engine = "InnoDB";
        $table->increments('id');
        $table->timestamps();
    });

    Schema::table('applications', function($table) {

        $table->integer('user_id')->unsigned()->index();
        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
        $table->integer('job_request_id')->unsigned()->index();
        $table->foreign('job_request_id')->references('id')->on('job_requests')->onDelete('cascade');
        $table->integer('status')->default(0);
    });
}

What I've already tried:

1.

public function up()
{
    Schema::create("applications", function(Blueprint $table) {
        $table->increments('id');
        $table->timestamps();

        $table->integer('user_id')->unsigned();
        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
        $table->integer('job_request_id')->unsigned();
        $table->foreign('job_request_id')->references('id')->on('job_requests')->onDelete('cascade');
        $table->integer('status')->default(0);
    });
}

2.

public function up()
{
    Schema::create("applications", function(Blueprint $table) {
        $table->engine = "InnoDB";
        $table->increments('id');
        $table->timestamps();

        $table->integer('user_id')->unsigned();
        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
        $table->integer('job_request_id')->unsigned();
        $table->foreign('job_request_id')->references('id')->on('job_requests')->onDelete('cascade');
        $table->integer('status')->default(0);
    });
}
  1. Splitting the migration into two files (A create and an alter). Even adding each reference one by one.

4.- using DB::statement('SET FOREIGN_KEY_CHECKS=0;'); and =1 at the beginning an the end og the migration.

5.- removing the unsigned() and the index().

Might mean something:

1.- When I rollback the migration, it doesn't delete the table. So if I rollback and migrate, would give me a "already exists error".

2.- I already have migrations which reference the same items, i.e:

Schema::create('job_requests', function (Blueprint $table) {
        ...
        $table->integer('user_id')->unsigned()->nullable();
        $table->foreign('user_id')->references('id')->on('users');
        ...
    });

UPDATE

For the drop methods I've tried:

  1. For the create migrations

    public function down() { Schema::drop('applications'); }

    public function down() { Schema::dropIfExists('applications'); }

2.- For the alter migrations

public function down()
{
    Schema::table('applications', function (Blueprint $table) {
        $table->dropForeign(['user_id']);
        $table->dropColumn('user_id');
        $table->dropForeign(['job_request_id']);
        $table->dropColumn('job_request_id');
    });
}

UPDATE 2:

public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->increments('id');
        $table->string('first_name');
        $table->string('last_name')->nullable();
        $table->string('password');
        $table->rememberToken();
        $table->timestamps();
    });
}

/**
 * Reverse the migrations.
 *
 * @return void
 */
public function down()
{
    Schema::dropIfExists('users');
}

public function up()
{
    Schema::create('job_requests', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('status')->default(0);
        $table->integer('user_id')->unsigned()->nullable();
        $table->foreign('user_id')->references('id')->on('users');
        $table->timestamps();
    });
}

/**
 * Reverse the migrations.
 *
 * @return void
 */
public function down()
{
    Schema::dropIfExists('job_requests');
}

I added three more alter migration:

public function up()
{
    Schema::table('users', function (Blueprint $table) {
        $table->engine = "InnoDB";
    });
}

///////////////////////////

public function up()
{
    Schema::table('job_requests', function (Blueprint $table) {
        $table->engine = "InnoDB";
    });
}

///////////////////////////

public function up()
{
    Schema::table('applications', function (Blueprint $table) {
        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
        $table->foreign('job_request_id')->references('id')->on('job_requests')->onDelete('cascade');
    });
}

/**
 * Reverse the migrations.
 *
 * @return void
 */
public function down()
{
    Schema::table('applications', function (Blueprint $table) {
        $table->dropForeign(['user_id']);
        $table->dropForeign(['job_request_id']);
    });
}

Without luck yet.

Upvotes: 1

Views: 1112

Answers (2)

Jonas Staudenmeir
Jonas Staudenmeir

Reputation: 25906

The referenced tables also have to use the InnoDB engine.

You can change them with raw SQL statements:

DB::statement("ALTER TABLE users ENGINE='InnoDB';");
DB::statement("ALTER TABLE job_requests ENGINE='InnoDB';");

Upvotes: 2

Hussein
Hussein

Reputation: 1153

for deleting the table:

public function down()
{
  Schema::disableForeignKeyConstraints();
  Schema::dropIfExists('applications');
}

Upvotes: 0

Related Questions