Comment tronquer une table en utilisant la Doctrine 2?

je suppose que je dois construire une requête native pour tronquer une table en utilisant Doctine2.

$emptyRsm = new DoctrineORMQueryResultSetMapping();
$sql = 'TRUNCATE TABLE Article';
$query = em()->createNativeQuery($sql, $emptyRsm);
$query->execute();

cela donne l'erreur

SQLSTATE[HY000]: General error

Que dois-je changer à mon code pour que cela fonctionne?

28
demandé sur martin 2012-03-13 19:19:30

4 réponses

attention aux Tables tronquées

méfiez-vous de tronquer les tables dans n'importe quel SGBDR, surtout si vous voulez utiliser des transactions explicites pour la fonctionnalité de commit/rollback.



instructions DDL effectuer un implicite-commit

les énoncés de table tronqués sont des énoncés de définition de données (DDL), et en tant que tels les énoncés de table tronqués déclenchent un implicite COMMIT à la base de données lors de leur exécution . Si vous exécutez un TABLE TRUNCATE alors la base de données est implicitement engagée à--même si le TABLE TRUNCATE est dans un START TRANSACTION statement--votre table sera tronquée et un ROLLBACK will pas le restaurer.

parce que les déclarations de table tronquées effectuent des commits implicites, la réponse de Maxence ne fonctionne pas comme prévu (mais ce n'est pas mal, parce que la question était "comment tronquer un tableau"). Sa réponse ne fonctionne pas comme prévu parce qu'elle tronque la table dans un bloc try , et suppose que la table peut être restaurée dans le bloc catch , si quelque chose va mal. C'est une hypothèse erronée.



commentaires et expériences d'autres utilisateurs dans ce fil de discussion

ChrisAelbrecht n'a pas pu obtenir la solution de Maxence pour fonctionner correctement parce que vous ne pouvez pas faire reculer un énoncé de table tronquée, même si l'énoncé de table tronquée est dans une transaction explicite.

user2130519, malheureusement, a été rétrogradé (-1 jusqu'à ce que je rétrograde) pour fournir la bonne réponse--bien qu'il l'ait fait sans justifier sa réponse, qui est comme faire des mathématiques sans montrer votre travail.



ma recommandation DELETE FROM

ma recommandation est d'utiliser DELETE FROM . Dans la plupart des cas, il fonctionnera comme le développeur. Mais, DELETE FROM ne vient pas sans inconvénients non plus--vous devez explicitement réinitialiser la valeur d'incrément automatique pour la table. Pour réinitialiser la valeur d'incrément automatique pour la table, vous devez utiliser une autre instruction DDL-- ALTER TABLE --et, encore une fois, n'utilisez pas ALTER TABLE dans votre bloc try . Il ne fonctionnera pas comme prévu.

si vous voulez des conseils sur quand vous devez utiliser DELETE FROM vs TRUNCATE voir pour & contre de tronquer vs Supprimer de .



Si vous devez vraiment, voici comment tronquer

maintenant, avec tout ce qui est dit. Si vous voulez vraiment tronquer une table en utilisant Doctrine2, utilisez ceci: (ci-dessous est la partie de la réponse de Maxence qui tronque correctement une table)

$cmd = $em->getClassMetadata($className);
$connection = $em->getConnection();
$dbPlatform = $connection->getDatabasePlatform();
$connection->query('SET FOREIGN_KEY_CHECKS=0');
$q = $dbPlatform->getTruncateTableSql($cmd->getTableName());
$connection->executeUpdate($q);
$connection->query('SET FOREIGN_KEY_CHECKS=1');



comment supprimer une table avec fonction rollback/commit.

mais, si vous voulez la fonctionnalité rollback/commit, vous devez utiliser DELETE FROM : (ci-dessous est une version modifiée de la réponse de Maxence.)

$cmd = $em->getClassMetadata($className);
$connection = $em->getConnection();
$connection->beginTransaction();

try {
    $connection->query('SET FOREIGN_KEY_CHECKS=0');
    $connection->query('DELETE FROM '.$cmd->getTableName());
    // Beware of ALTER TABLE here--it's another DDL statement and will cause
    // an implicit commit.
    $connection->query('SET FOREIGN_KEY_CHECKS=1');
    $connection->commit();
} catch (\Exception $e) {
    $connection->rollback();
}

si vous devez réinitialiser la valeur d'incrément automatique, n'oubliez pas d'appeler ALTER TABLE <tableName> AUTO_INCREMENT = 1 .

75
répondu cmt 2017-05-23 10:30:11

voici le code que j'utilise:

$cmd = $em->getClassMetadata($className);
$connection = $em->getConnection();
$dbPlatform = $connection->getDatabasePlatform();
$connection->beginTransaction();
try {
    $connection->query('SET FOREIGN_KEY_CHECKS=0');
    $q = $dbPlatform->getTruncateTableSql($cmd->getTableName());
    $connection->executeUpdate($q);
    $connection->query('SET FOREIGN_KEY_CHECKS=1');
    $connection->commit();
}
catch (\Exception $e) {
    $connection->rollback();
}
35
répondu Maxence 2012-03-14 21:14:48

ou vous pourriez juste essayer ceci:

$this->getEm()->createQuery('DELETE AcmeBundle:Post p')->execute();

si vous avez des relations, vous devez faire attention aux entités liées.

12
répondu piers.warmers 2017-06-28 07:27:46

il s'agit d'un exemple de méthode de tronçonnage de trait dans les essais unitaires.

/**
 * Cleanup any needed table abroad TRUNCATE SQL function
 *
 * @param string $className (example: App\Entity\User)
 * @param EntityManager $em
 * @return bool
 */
private function truncateTable (string $className, EntityManager $em): bool {
    $cmd = $em->getClassMetadata($className);
    $connection = $em->getConnection();
    $connection->beginTransaction();

    try {
        $connection->query('SET FOREIGN_KEY_CHECKS=0');
        $connection->query('TRUNCATE TABLE '.$cmd->getTableName());
        $connection->query('SET FOREIGN_KEY_CHECKS=1');
        $connection->commit();
        $em->flush();
    } catch (\Exception $e) {
        try {
            fwrite(STDERR, print_r('Can\'t truncate table ' . $cmd->getTableName() . '. Reason: ' . $e->getMessage(), TRUE));
            $connection->rollback();
            return false;
        } catch (ConnectionException $connectionException) {
            fwrite(STDERR, print_r('Can\'t rollback truncating table ' . $cmd->getTableName() . '. Reason: ' . $connectionException->getMessage(), TRUE));
            return false;
        }
    }
    return true;
}

s'il vous Plaît noter, que si vous n'utilisez pas $em->flush() , vous avez un risque d'avoir un problème avec la requête suivante à la doctrine.

vous devez également comprendre que si vous utilisez cette méthode dans un contrôleur, vous devez changer les lignes fwrite(STDERR, print_r(... en quelque chose que votre service logger peut utiliser.

0
répondu Borys Ermokhin 2018-08-10 13:34:08