简体   繁体   中英

Laravel 5 Migration Error Related to Foreign Key

This is an attempt to learn Laravel (specifically v5.x) by porting an old project using a SQL dump that contains this:

CREATE TABLE IF NOT EXISTS `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `locationid` int(11) NOT NULL,
  `username` varchar(45) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL,
  `email` varchar(200) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL,
  `firstname` varchar(100) NOT NULL,
  `lastname` varchar(100) NOT NULL,
  `password` varchar(255) NOT NULL,
  `active` bit(1) DEFAULT b'1',
  `token` varchar(100) DEFAULT NULL,
  `token_created` timestamp NULL DEFAULT NULL,
  `role` varchar(45) NOT NULL DEFAULT 'user',
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `email_UNIQUE` (`email`),
  UNIQUE KEY `username_UNIQUE` (`username`),
  KEY `location_idx` (`locationid`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

And at the bottom of the dump had this related to this specific table:

ALTER TABLE `user`
  ADD CONSTRAINT `location_userfk` FOREIGN KEY (`locationid`) REFERENCES `location` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;

From a couple stackoverflow questions 1 , 2 , 3 ; I've altered my original code to split out the foreign key to Schema::table from Schema::create and added unsigned() to each of the fields:

public function up()
{
    Schema::create('users', function(Blueprint $table)
    {
        $table->increments('id');
        $table->integer('locationid')->unsigned();
        // $table->foreign('locationid')->references('id')->on('location');
        $table->string('username', 60)->unique();
        $table->string('email', 200)->unique();
        $table->string('firstname', 100);
        $table->string('lastname', 100);
        $table->string('password', 255);
        $table->boolean('active')->default(TRUE);
        $table->string('role', 45)->default('user');
        // $table->string('token', 255)->nullable()->default(NULL);
        // $table->string('token_create')->nullable()->default(NULL);
        $table->rememberToken();
        $table->timestamps();
    });

    Schema::table('users', function(Blueprint $table) 
    {
        $table->foreign('locationid')->references('id')->on('location');
    });
}

But I still get an error when I migrate when using an empty newly created DB:

exception 'PDOException' with message 'SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint' in /home/vagrant/projects/communityfuturesbc/vendor/laravel/framework/src/Illuminate/Database/Connection.php:358
Stack trace:
#0 /home/vagrant/projects/communityfuturesbc/vendor/laravel/framework/src/Illuminate/Database/Connection.php(358): PDOStatement->execute(Array) etc...

Next exception 'Illuminate\Database\QueryException' with message 'SQLSTATE[HY000]: General err
or: 1215 Cannot add foreign key constraint (SQL: alter table `users` add constraint users_loca
tionid_foreign foreign key (`locationid`) references `location` (`id`))' in /home/vagrant/proj
ects/communityfuturesbc/vendor/laravel/framework/src/Illuminate/Database/Connection.php:614   
Stack trace:                                                                                  
#0 /home/vagrant/projects/communityfuturesbc/vendor/laravel/framework/src/Illuminate/Database/Connection.php(570): Illuminate\Database\Connection->runQueryCallback('alter table `us...', Ar
ray, Object(Closure))

Which according to MySQL means:

Error: 1215 SQLSTATE: HY000 (ER_CANNOT_ADD_FOREIGN)
Message: Cannot add foreign key constraint                                         

After which I can't rollback or migrate again without getting another type of error regarding the existence of users table already in the DB so each time I try a version of the above code I've been dropping my DB each time.

I'm sure after fixing this it will occur in all the other tables, which are similar or have more than one foreign key so hopefully whatever fixes this will work for the rest.

You have to change the migrations order

|-database/
|--migrations/
|---2015_02_02_141725_create_users_table.php
|---2015_03_01_234626_create_locations_table.php

Should be:

|-database/
|--migrations/
|---2015_01_01_234626_create_locations_table.php
|---2015_02_02_141725_create_users_table.php

Finally:

php artisan migrate

The error is caused by the migration which tries to reference on an non existing column. To prevent this issue create referenced column before performing the foreign key creation.

To create table structures with dependencies you can either create the migration files in the correct order, or put all migrations into one big file or at least create all tables without foreign keys and create another file which performs the key-creation in the end. Keep in min this is only necessary if you want to rescript an existing data structure or want to fix the migration order. Otherwise use the php artisan make:migration command.

I had the same problem, what did I do?

simple... in your create_users migration file try this....

public function up()
{

Schema::create('location', function(Blueprint $table)
{
    $table->increments('id');
    ...other attributes... 
    $table->rememberToken();
    $table->timestamps();
});

Schema::create('users', function(Blueprint $table)
{
    $table->increments('id');
    $table->integer('locationid')->unsigned();
    $table->string('username', 60)->unique();
    $table->string('email', 200)->unique();
    $table->string('firstname', 100);
    $table->string('lastname', 100);
    $table->string('password', 255);
    $table->boolean('active')->default(TRUE);
    $table->string('role', 45)->default('user');
    // $table->string('token', 255)->nullable()->default(NULL);
    // $table->string('token_create')->nullable()->default(NULL);
    $table->rememberToken();
    $table->timestamps();
});

Schema::table('users', function(Blueprint $table) 
{
    $table->foreign('locationid')->references('id')->on('location');
});}

:)

Well, its little confusing part here, first create an table('users') when up method run and then respectively update table('users') by adding in Foreign key in the same table. I think its can not perform at the same time add and update using migration. For the solution of your code would be:

public function up()
{
    Schema::create('users', function(Blueprint $table)
    {
        //...
        $table->integer('locationid')->unsigned();
        $table->foreign('locationid')->references('id')->on('location');
        //...
    });
}

Now, you creating your foreign by creating your table. so its should work if not let me know.

Make sure your location table exists first. Referencing a non existing table can cause the error you're having.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM