Как обрезать таблицу с помощью Doctrine 2? - PullRequest
29 голосов
/ 13 марта 2012

Я предполагаю, что мне нужно создать собственный запрос для усечения таблицы с использованием Doctine2.

$emptyRsm = new \Doctrine\ORM\Query\ResultSetMapping();
$sql = 'TRUNCATE TABLE Article';
$query = em()->createNativeQuery($sql, $emptyRsm);
$query->execute();

Это дает ошибку

SQLSTATE[HY000]: General error

Что мне нужно изменить в своем коде, чтобы это работало?

Ответы [ 4 ]

80 голосов
/ 12 июня 2013

Остерегайтесь усеченных столов

Остерегайтесь усеченных таблиц в любой СУБД, особенно если вы хотите использовать явные транзакции для функции фиксации / отката.


Операторы DDL выполняют неявную фиксацию

Операторы усеченной таблицы являются операторами языка определения данных (DDL), и поэтому Операторы усеченной таблицы вызывают неявное COMMIT для базы данных при их выполнении . Если вы выполняете TABLE TRUNCATE, то база данных неявно фиксируется - даже если TABLE TRUNCATE находится внутри оператора START TRANSACTION - ваша таблица будет усечена, а ROLLBACK будет не восстанавливать это.

Поскольку операторы усеченной таблицы выполняют неявные коммиты, Ответ Maxence не работает должным образом (но это не так, потому что вопрос был «как усечь таблицу»). Его ответ не работает должным образом, поскольку он усекает таблицу в блоке try и предполагает, что таблица может быть восстановлена ​​в блоке catch, если что-то пойдет не так. Это неверное предположение.


Комментарии других пользователей в этой теме

ChrisAelbrecht не удалось заставить решение Maxence работать должным образом, потому что вы не можете откатить оператор таблицы усечения, даже если оператор таблицы усечения находится в явной транзакции.

user2130519, к сожалению, был понижен (-1, пока я не проголосовал) за предоставление правильного ответа - хотя он сделал это без обоснования своего ответа, что похоже на выполнение математики без показа вашей работы.


Моя рекомендация DELETE FROM

Я рекомендую использовать DELETE FROM. В большинстве случаев он будет работать так, как ожидает разработчик. Но DELETE FROM также не имеет недостатков - вы должны явно сбросить значение автоинкремента для таблицы. Чтобы сбросить значение автоматического приращения для таблицы, вы должны использовать другой оператор DDL - ALTER TABLE - и, опять же, не использовать ALTER TABLE в своем блоке try. Это не будет работать, как ожидалось.

Если вы хотите узнать, когда следует использовать DELETE FROM против TRUNCATE, см. Плюсы и минусы TRUNCATE против DELETE FROM .


Если вам действительно нужно, вот как обрезать

Теперь со всем, что сказано. Если вы действительно хотите обрезать таблицу с помощью Doctrine2, используйте это: (Ниже приведена часть ответа Maxence, которая правильно обрезает таблицу)

$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');


Как удалить таблицу с возможностью отката / фиксации.

Но, если вы хотите использовать функцию отката / фиксации, вы должны использовать DELETE FROM: (Ниже приведена измененная версия ответа 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();
}

Если вам нужно сбросить значение автоинкремента, не забудьте вызвать ALTER TABLE <tableName> AUTO_INCREMENT = 1.

37 голосов
/ 15 марта 2012

Вот код, который я использую:

$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();
}
12 голосов
/ 04 марта 2013

Или вы можете просто попробовать это:

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

Если у вас есть отношения, вы должны быть осторожны при работе со связанными сущностями.

0 голосов
/ 10 августа 2018

Это пример метода усечения по признаку в модульных тестах.

/**
 * 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;
}

Обратите внимание, что если вы не используете $em->flush(), у вас есть риск возникновения проблемы со следующим запросом к доктрине.

Также вы должны понимать, что если вы используете этот метод в контроллере, вы должны изменить строки fwrite(STDERR, print_r(... на то, что может использовать ваша служба регистрации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...