15

I have a many-to-many relationship between User & Role, with a role_user table. My migrations are setup as so (simplified):

users table:

public function up()
{
    Schema::create('users', function(Blueprint $table)
    {
        $table->increments('id');
        $table->string('email')->unique();
    });
}

roles table:

public function up()
{
    Schema::create('roles', function(Blueprint $table)
    {
        $table->increments('id');
        $table->string('name');
    });
}

role_user table:

public function up()
{
    Schema::create('role_user', function(Blueprint $table)
    {
        $table->increments('id');
        $table->integer('user_id')->unsigned();
        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
        $table->integer('role_id')->unsigned();
        $table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');
    });
}

So as per the docs, I set my foreign keys to unsigned.

Now, I add a couple of users, and attach some roles - everything works fine. However, when I delete a user (User::destroy(2)) the rows for that user in the role_user table do not get deleted, which is causing redundant rows.

What am I doing wrong?

  • MySQL + InnoDB

EDIT: Grabbing the model and applying ->delete(); also has the same effect.

Alias
  • 2,983
  • 7
  • 39
  • 62
  • Have you relationships created in MySQL? Check your table structure in software like PHPMyAdmin. Also try to remove `$table->integer('user_id')->unsigned();` – Mateusz Nowak Jul 22 '14 at 21:21
  • I have PHPMyAdmin installed - where do I view the relationships? Will have a gander. – Alias Jul 22 '14 at 21:23
  • http://www.binarytides.com/blog/wp-content/uploads/2009/08/phpmyadmin_relation_view-600x443.png This may help – Mateusz Nowak Jul 22 '14 at 21:25
  • Nope nothing there. Confusing... no errors are thrown during migrations. – Alias Jul 22 '14 at 21:27
  • So there isn't any relationship marked in PHPMyAdmin? Something must be wrong with schema in this case. I would turn logging queries on and check them during migration. – Mateusz Nowak Jul 22 '14 at 21:31
  • 4
    Okay, I manually set `$table->engine = 'InnoDB';` and now it's working, even though it says "InnoDB" under the "type" column in the DB. Weird. – Alias Jul 22 '14 at 21:39
  • Check once again queries. There will be problem described. If it's is a bug with table engine please report it on laravel github. Good luck with your application. – Mateusz Nowak Jul 22 '14 at 21:41
  • I've found this issue, and the comment above about setting the table engine manually fixed the issue. I have filed a bug: https://github.com/laravel/framework/issues/8730 – Jake May 13 '15 at 21:01

6 Answers6

20

Try setting when trying to create this table. This fix has worked for me.

$table->engine = 'InnoDB';

I have filed a bug under: https://github.com/laravel/framework/issues/8730

Jake
  • 775
  • 9
  • 17
  • This problem occurs most probably because the default table engine in your MySQL instance is set to MyISAM which doesn't support foreign keys. Trying to work with foreign keys on a MyISAM table would definitely not be a bug in Laravel. Although it would be nice if the Schema Builder could automatically set the engine to InnoDB if foreign keys are used. – Hugo St-Arnaud Oct 13 '16 at 16:01
  • Make sure you add it to all migrations or it would not work. – Jeffrey May 06 '17 at 21:37
  • Who still uses MyISAM though :) – Jeremy Belolo Jul 25 '21 at 21:00
12

It is established by Jake's answer that you have set default engine to InnoDB

$table->engine = 'InnoDB';

Instead of doing it in each migration file, You can do so in config/database.php

'mysql' => [
        'driver' => 'mysql',
        'host' => env('DB_HOST', '127.0.0.1'),
        'port' => env('DB_PORT', '3306'),
        'database' => env('DB_DATABASE', 'forge'),
        'username' => env('DB_USERNAME', 'forge'),
        'password' => env('DB_PASSWORD', ''),
        'unix_socket' => env('DB_SOCKET', ''),
        'charset' => 'utf8mb4',
        'collation' => 'utf8mb4_unicode_ci',
        'prefix' => '',
        'strict' => false,
        'engine' => 'InnoDB',
    ],
Shreyansh Panchal
  • 827
  • 12
  • 22
  • 1
    To add to Shreyansh's answer this is faster but you need to restart your localhost:8000 then run `php artisan migrate:fresh` Of course back up your data first. – KD_Raj May 30 '20 at 18:30
5

Check the MySQL config. my.ini may still have default-storage-engine=MYISAM. Set to default-storage-engine=InnoDB and you should avoid the trouble of adding this fix to each migration.

Udhav Sarvaiya
  • 9,380
  • 13
  • 53
  • 64
STWilson
  • 1,538
  • 2
  • 16
  • 26
  • 1
    After changing `my.ini` on local dev machine under Windows & WAMP do not forget to restart the WAMP services (left-click on taskbar icon and select **Restart All Services**) – Valentine Shi Jul 13 '19 at 09:45
5

I know this is an old issue, but recently (on Laravel 8) I had the same problem even when using InnoDB.

I solved it by using the constrained() option on the relationship. Without the "constrained" parameter, the migration won't create the actual relationship on the database.

$table->foreignId('user_id')->constrained()->onDelete('cascade');
Sid Benetti
  • 61
  • 1
  • 3
3

For someone that's here and using SoftDeletes on their models; onDelete('cascade') functionality is lost when using SoftDeletes. Options you could use in such a case are:

  1. Using dyrynda/laravel-cascade-soft-deletes package to handle this for you.
  2. Using Eloquent Events to trigger an event that the parent has been deleted and handle the deletion of the child rows yourself.
Sammie
  • 1,551
  • 1
  • 21
  • 17
  • https://laracasts.com/discuss/channels/laravel/laravel-soft-delete-cascade Here is an example well explained. – tinystone Aug 15 '23 at 05:06
0

even after changing the engine to InnoDB in Config->Database it does not work

and the solution for that is to change the migration

From

Schema::create('users', function (Blueprint $table) { $table->BigIncrements('id');

To

Schema::create('users', function (Blueprint $table) { $table->increments('id');

Muaath Alhaddad
  • 341
  • 2
  • 14
  • I really don't think that changing `BigIncrements` to `increments` is a desired answer. The bigInteger method creates a `BIGINT` equivalent column And The `increments` method creates an auto-incrementing UNSIGNED INTEGER equivalent column as a primary key. – Shreyansh Panchal Dec 17 '20 at 08:56