web-dev-qa-db-ja.com

Doctrine QueryBuilderは結合で削除します

Doctrine QueryBuilderを使用して、次のSQLクエリを実行しようとしています。

DELETE php FROM product_hole_pattern php
INNER JOIN hole_pattern hp ON php.hole_pattern_id = hp.id
INNER JOIN hole_pattern_type hpt ON hp.hole_pattern_type_id = hpt.id
WHERE php.product_id = 4 AND hpt.slug='universal';

私はこれを持っています

$qb = $this->entityManager->createQueryBuilder();
$query = $qb->delete('\SANUS\Entity\ProductHolePattern', 'php')
  ->innerJoin('php.holePattern', 'hp')
  ->innerJoin('hp.holePatternType', 'hpt')
  ->where('hpt.slug = :slug AND php.product=:product')
  ->setParameter('slug','universal')
  ->setParameter('product',$this->id)
  ->getQuery();

しかし、私は得る:

[Semantical Error] line 0, col 50 near 'hpt.slug = :slug': Error: 'hpt' is not defined.

エラーメッセージに付属するDQLは次のとおりです。

DELETE \SANUS\Entity\ProductHolePattern php 
WHERE hpt.slug = :slug AND php.product=:product

したがって、結合は完全に省略されているようです。

14
Chris Hanson

反復するよりも、IN条件でクエリを実行する方がよい場合があります。

$ids = $this->createQueryBuilder('product')
->join('..your joins..')
->where('..your wheres..')
->select('product.id')
->getQuery()->getResult();

$this->createQueryBuilder('product')
    ->where('product.id in (:ids)')
    ->setParameter('ids', $ids)
    ->delete()
    ->getQuery()
    ->execute();
  • 利点:実行速度が速く、反復する必要がありません
  • 欠点:preRemoveにフックすることはできません

「どこに置くか」という白熱した議論については、必要に応じてあえてコントローラーに入れてください。それは完全にあなた次第です。ただし、コードを専用のdoctrineリポジトリクラスに配置すると、将来的にはさらに便利になる可能性があります。これは非常に簡単で、変更/保守も簡単です。

6
kshishkin

DQLはこの種の削除ステートメントをサポートしていないようです。 Doctrineドキュメント からのBNFは、delete_statement形式をとる必要があります

delete_clause [where_clause]

どこ delete_clause と定義されている:

"DELETE" "FROM" abstract_schema_name [["AS"] identification_variable]

したがって、スキーマとwhere句を提供できますが、結合は提供できません。

11
Chris Hanson

これを実現する方法は、最初に結合を使用して削除するエンティティをクエリすることです。

$qb = $this->entityManager->createQueryBuilder();
$query = $qb->select('\SANUS\Entity\ProductHolePattern', 'php')
  ->innerJoin('php.holePattern', 'hp')
  ->innerJoin('hp.holePatternType', 'hpt')
  ->where('hpt.slug = :slug AND php.product=:product')
  ->setParameter('slug','universal')
  ->setParameter('product',$this->id)
  ->getQuery();
$results = $query->execute();

次に、結果で見つかったエンティティを削除します。

foreach ($results as $result) {
  $this->entityManager->remove($result);
}

必ずお電話ください

$this->entityManager->flush();

アプリケーションの適切な場所(通常はコントローラー)。

8