data-fixtures icon indicating copy to clipboard operation
data-fixtures copied to clipboard

Support truncating tables with foreign keys

Open Seldaek opened this issue 12 years ago • 10 comments

I had to override the loadFixtures method of the LiipFunctionalTestBundle with this stuff to avoid blowing up mysql:

    protected function loadFixtures(array $classNames, $omName = null, $registryName = 'doctrine', $purgeMode = null)
    {
        $conn = $this->getContainer()->get($registryName)->getManager()->getConnection();
        $db = $conn->getDriver()->getDatabasePlatform()->getName();
        if ($db === 'mysql') {
            $conn->exec('SET FOREIGN_KEY_CHECKS=0');
        }
        $res = parent::loadFixtures($classNames, $omName, $registryName, $purgeMode);
        if ($db === 'mysql') {
            $conn->exec('SET FOREIGN_KEY_CHECKS=1');
        }

        return $res;
    }

Now obviously it could be integrated in the bundle (cc @lsmith77) but ideally it would be part of this library itself so everyone benefits. Not sure how/where to best do this though, so I'm dropping this here hoping someone will pick it up :)

Seldaek avatar Sep 12 '13 15:09 Seldaek

@Seldaek turning off FK checks in fixtures? Sounds seriously broken... What about the other engines? Is it just a MySQL bug?

Ocramius avatar Sep 12 '13 15:09 Ocramius

we need to somehow generalize this, its a MySQL problem AFAIK, not sure about other databases. We need to reproduce this in DBAL for sure.

beberlei avatar Sep 12 '13 15:09 beberlei

the big issue in MySQL is that they do FK checks after every statement rather than at the end of the transaction. so yeah most other RDBMS support so called deferred FKs and therefore do not suffer from this.

lsmith77 avatar Sep 12 '13 15:09 lsmith77

Sorry I should have clarified. This is not about disabling FK checks for the whole loading of fixtures, the only thing we need is to disable them while running the ORMPurger because it does TRUNCATE and that is not supported with FK checks enabled.

Seldaek avatar Sep 12 '13 15:09 Seldaek

This really is a poking issue. Almost all my CI projects are now failing after an update to MySQL >= 5.5.7 (the version where this behavior of TRUNCATE was introduced). For reference here are the discussions on mysql: http://bugs.mysql.com/bug.php?id=58788 and http://bugs.mysql.com/bug.php?id=58788

I hope that you can find a solution in a timely manner since more and more people will be upgrading mysql for sure.

tPl0ch avatar Sep 21 '13 04:09 tPl0ch

+1 this need to be resolved

tiger-seo avatar Nov 20 '14 20:11 tiger-seo

+1

theofidry avatar Sep 22 '15 08:09 theofidry

The only way to fiddle with this issue (as both MySQL won't fix it nor doctrine DBAL willing to add another vendor specific rule) for me was to create a special DBAL driver and use this during fixture loading.

https://coderwall.com/p/staybw/workaround-for-1701-cannot-truncate-a-table-referenced-in-a-foreign-key-constraint-using-doctrine-fixtures-load-purge-with-truncate gives some hints.

In Symfony I ended up using a config_fixtures.yml, passing the doctrine:fixtures:load env=fixtures where this special Driver is used

config_fixtures.yml

...
doctrine: 
    dbal: 
        driver_class: AppBundle\DBAL\Driver

Driver.php

<?php

namespace AppBundle\DBAL;

use Doctrine\DBAL\Driver\PDOMySql\Driver as BaseDriver;

class Driver extends BaseDriver
{
    /**
     * {@inheritdoc}
     */
    public function getDatabasePlatform()
    {
        return new Platform();
    }
}

Platform.php

<?php

namespace AppBundle\DBAL;

use Doctrine\DBAL\Platforms\MySqlPlatform;

class Platform extends MySqlPlatform
{
    /**
     * {@inheritdoc}
     */
    public function getTruncateTableSQL($tableName, $cascade = false)
    {
        return sprintf('SET foreign_key_checks = 0;TRUNCATE %s;SET foreign_key_checks = 1;', $tableName);
    }
}

fschaeffer avatar Oct 02 '15 08:10 fschaeffer

@fschaeffer With your workaround, I get the following error:

 [Symfony\Component\Config\Definition\Exception\InvalidConfigurationException]  
  Unrecognized option "driver_class" under "doctrine.dbal"                       

My doctrine dbal config:

doctrine:
    dbal:
        driver_class: AppBundle\DBAL\Driver
        default_connection: default
        connections:
            default:
                driver:   pdo_mysql
                host:     "%database_host%"
                port:     "%database_port%"
                dbname:   "%database_name%"
                user:     "%database_user%"
                password: "%database_password%"
                charset:  UTF8

            powerdns:
                driver:   pdo_mysql
                host:     "%powerdns_host%"
                port:     "%powerdns_port%"
                dbname:   "%powerdns_name%"
                user:     "%powerdns_user%"
                password: "%powerdns_password%"
                charset:  UTF8
        types:
            json: Sonata\Doctrine\Types\JsonType

Any idea?

soullivaneuh avatar Oct 05 '15 14:10 soullivaneuh

Ok I get it, it's because I have multiple connections definitions. I have to specify it on each connection:

doctrine:
    dbal:
        default_connection: default
        connections:
            default:
                driver_class: AppBundle\DBAL\Driver
                driver:   pdo_mysql
                host:     "%database_host%"
                port:     "%database_port%"
                dbname:   "%database_name%"
                user:     "%database_user%"
                password: "%database_password%"
                charset:  UTF8

soullivaneuh avatar Oct 05 '15 14:10 soullivaneuh