37

Doctine2 を使用してテーブルを切り捨てるネイティブ クエリを作成する必要があるとします。

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

これにより、エラーが発生します

SQLSTATE[HY000]: General error

これを機能させるには、コードに何を変更する必要がありますか?

4

5 に答える 5

93

テーブルの切り捨てに注意する

特にコミット/ロールバック機能に明示的なトランザクションを使用する場合は、RDBMS でのテーブルの切り捨てに注意してください。この回答の「私の推奨事項」をお読みください。


DDL ステートメントは暗黙的なコミットを実行します

Truncate table ステートメントはデータ定義言語 (DDL) ステートメントであり、そのため、truncate table ステートメントは実行時にデータベースへの暗黙的な をトリガーしCOMMITます。a を実行するTABLE TRUNCATEと、データベースは暗黙的にコミットされます。これがステートメントTABLE TRUNCATE内にある場合でもSTART TRANSACTION、テーブルは切り捨てられ、 aROLLBACKは復元しません。

truncate table ステートメントは暗黙的なコミットを実行するため、Maxence の回答は期待どおりに実行されません(ただし、質問は「テーブルを切り捨てる方法」だったので、間違っていません)。彼の答えは、ブロック内のテーブルを切り捨て、何か問題が発生した場合tryにテーブルをブロック内で復元できると想定しているため、期待どおりに機能しません。catchこれは間違った仮定です。


このスレッドでの他のユーザーのコメントと経験

ChrisAelbrecht は Maxence のソリューションを適切に機能させることができませんでした。これは、truncate table ステートメントが明示的なトランザクション内にある場合でも、truncate table ステートメントをロールバックできないためです。

残念ながら、user2130519 は、正しい答えを提供したことで反対票を投じられました (私が賛成票を投じるまで -1)。


私のおすすめDELETE FROM

私のお勧めは、 を使用することDELETE FROMです。ほとんどの場合、開発者の期待どおりに動作します。ただし、DELETE FROM欠点がないわけではありません。テーブルの自動インクリメント値を明示的にリセットする必要があります。テーブルの自動インクリメント値をリセットするには、別の DDL ステートメントを使用する必要があります。また、ブロック内でALTER TABLEは使用しないALTER TABLEでください。try期待どおりに動作しません。

いつ使用する必要があるかについてのヒントが必要な場合は、 DELETE FROMTRUNCATEと DELETE FROM の長所と短所をTRUNCATE参照してください。


本当に必要な場合は、切り捨てる方法を次に示します

さて、それですべてです。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ください。

于 2013-06-12T14:39:15.150 に答える
40

私が使用しているコードは次のとおりです。

$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();
}
于 2012-03-14T21:14:48.980 に答える
11

または、これを試すこともできます:

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

リレーションがある場合は、リンクされたエンティティの取り扱いに注意する必要があります。

于 2013-03-04T05:06:34.313 に答える