Doctine2を使用してテーブルを切り捨てるネイティブクエリを作成する必要があると思います。
$emptyRsm = new \Doctrine\ORM\Query\ResultSetMapping();
$sql = 'TRUNCATE TABLE Article';
$query = em()->createNativeQuery($sql, $emptyRsm);
$query->execute();
これはエラーを与えます
SQLSTATE[HY000]: General error
この作業を行うには、コードに何を変更する必要がありますか?
特にコミット/ロールバック機能に明示的なトランザクションを使用する場合は、RDBMS内のテーブルの切り捨てに注意してください。
Truncate Tableステートメントはデータ定義言語(DDL)ステートメントであるため、Truncate Tableステートメントは、実行時にデータベースへの暗黙的なCOMMIT
をトリガーします。 TABLE TRUNCATE
を実行すると、TABLE TRUNCATE
がSTART TRANSACTION
ステートメント内にある場合でも、データベースは暗黙的にコミットされ、テーブルは切り捨てられ、ROLLBACK
not復元しません。
Truncate tableステートメントは暗黙的なコミットを実行するため、Maxenceの答えは期待どおりに実行されません(ただし、質問は「テーブルを切り捨てる方法」だったため、間違っていません)。彼の答えはtry
ブロック内のテーブルを切り捨て、問題が発生した場合にcatch
ブロック内でテーブルを復元できると想定しているため、期待どおりに機能しません。これは間違った仮定です。
ChrisAelbrechtは、truncate tableステートメントが明示的なトランザクション内にある場合でも、truncate tableステートメントをロールバックできないため、Maxenceのソリューションを適切に動作させることができませんでした。
user2130519は、残念なことに、正しい答えを提供したことでダウンボットされました(私がアップボットするまで-1)。ただし、彼は答えを正当化せずにそうしました。
DELETE FROM
私の推奨はDELETE FROM
を使用することです。ほとんどの場合、開発者が期待するとおりに機能します。ただし、DELETE FROM
にも欠点はありません。テーブルの自動インクリメント値を明示的にリセットする必要があります。テーブルの自動インクリメント値をリセットするには、別のDDLステートメントを使用する必要があります--ALTER TABLE
--そして、再度、try
ブロックでALTER TABLE
を使用しないでください。期待どおりに動作しません。
DELETE FROM
vs 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
を呼び出すことを忘れないでください。
私が使用しているコードは次のとおりです。
$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();
}
または、これを試すことができます:
$this->getEm()->createQuery('DELETE AcmeBundle:Post p')->execute();
関係がある場合は、リンクされたエンティティを慎重に処理する必要があります。
これは、単体テストで特性からメソッドを切り捨てる例です。
_/**
* 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(...
_をロガーサービスが使用できるものに変更する必要があることを理解する必要があります。