WillyCornelissen's avatar

Foreign Key Constraints on seeding

when I am running a db:seed I disabled foreign key constraints on DatabaseSeeder.php:

    Model::unguard();
    DB::statement('SET FOREIGN_KEY_CHECKS=0;');
    $this->call('UsersTableSeeder');
    ........
    DB::statement('SET FOREIGN_KEY_CHECKS=1;');

It works fine with MySQL, but if I change the database configuration to sqlite I got the following error:

SQLSTATE[HY000]: General error: 1 near "SET": syntax error (SQL: SET FOREIGN_KEY_CHECKS=0;

If I change the database configuration to postgres I got the following error:

[Illuminate\Database\QueryException]
SQLSTATE[42704]: Undefined object: 7 ERROR: unrecognized configuration parameter "foreign_key_checks" (SQL: SET FOREIGN_KEY_CHECKS=0;)

Any idea of what's going on?

0 likes
7 replies
rdelorier's avatar

The different database driver all have different syntax for setting the check value. Postgres is a little more difficult but this should work for mysql and sqlite. just add a use statement to your seeder and call the disable/enable function

<?php

trait DisablesForeignKeys {

    private $commands = [
        'mysql' => [
            'enable' => 'SET FOREIGN_KEY_CHECKS=1;',
            'disable' => 'SET FOREIGN_KEY_CHECKS=0;',
        ],
        'sqlite' => [
            'enable' => 'PRAGMA foreign_keys = ON;',
            'disable' => 'PRAGMA foreign_keys = OFF;',
        ]
    ];

    /**
     * Disable foreign key checks for current db driver
     */
    protected function disableForeignKeys()
    {
        DB::statement($this->getDisableStatement());
    }

    /**
     * Enable foreign key checks for current db driver
     */
    protected function enableForeignKeys()
    {
        DB::statement($this->getEnableStatement());
    }

    /**
     * Return current driver enable command
     * @return mixed
     */
    private function getEnableStatement()
    {
        return $this->getDriverCommands()['enable'];
    }

    /**
     * Return current driver disable command
     * @return mixed
     */
    private function getDisableStatement()
    {
        return $this->getDriverCommands()['disable'];
    }

    /**
     * Returns command array for current db driver
     * @return mixed
     */
    private function getDriverCommands()
    {
        return $this->commands[DB::getDriverName()];
    }
}
3 likes
XenitXTD's avatar

Here is a postgres 9+ Solution

https://stackoverflow.com/questions/38112379/disable-postgresql-foreign-key-checks-for-migrations

this part

For migration, it is easier to disable all triggers with:

SET session_replication_role = 'replica';

And after migration reenable all with

SET session_replication_role = 'origin';

I have my seeder set as follows


if (App::environment() === 'production') {
            exit('I just stopped you getting fired. Love Phil');
        }

        // Disable mass-assignment protection with Laravel
        Eloquent::unguard();

        $tables = [
            'users',
            'anothers',
        ];

        // Maria DB
        // DB::statement('SET FOREIGN_KEY_CHECKS=0;');
        // Postgres
        // DB::statement('DISABLE TRIGGER ALL;'); // Old
        DB::statement('SET session_replication_role = \'replica\';');

        foreach ($tables as $table)
        {
            DB::table($table)->truncate();
        }

        // Maria DB
        // DB::statement('SET FOREIGN_KEY_CHECKS=1;');
        // Postgres
        // DB::statement('ENABLE TRIGGER ALL;'); // Old
        DB::statement('SET session_replication_role = \'origin\';');

        $this->call(UsersTableSeeder::class);
        $this->call(AnothersTableSeeder::class);

        Eloquent::reguard();

2 likes
renusingh's avatar

What should be done with sqlserver? need help.

pgogy's avatar

I’m new and trying to work out seeding with foreign keys. Is the best way to disable the foreign keys?

Please or to participate in this conversation.