Doctrine QueryBuilder用连接删除

Chr*_*son 13 php mysql query-builder doctrine-orm

我正在尝试使用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';
Run Code Online (Sandbox Code Playgroud)

我有这个

$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();
Run Code Online (Sandbox Code Playgroud)

但我得到:

[Semantical Error] line 0, col 50 near 'hpt.slug = :slug': Error: 'hpt' is not defined.
Run Code Online (Sandbox Code Playgroud)

错误消息附带的DQL是:

DELETE \SANUS\Entity\ProductHolePattern php 
WHERE hpt.slug = :slug AND php.product=:product
Run Code Online (Sandbox Code Playgroud)

所以连接似乎完全被省略了.

Chr*_*son 11

看起来DQL不支持这种删除语句.来自Doctrine文档BNF表明delete_statement必须采用该形式

delete_clause [where_clause]
Run Code Online (Sandbox Code Playgroud)

在哪里delete_clause定义为:

"DELETE" "FROM" abstract_schema_name [["AS"] identification_variable]
Run Code Online (Sandbox Code Playgroud)

所以我可以提供一个schema和一个where子句,但是没有连接.


Dan*_*ant 9

完成此操作的方法可能是首先使用连接查询要删除的实体:

$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();
Run Code Online (Sandbox Code Playgroud)

然后删除在结果中找到的实体:

foreach ($results as $result) {
  $this->entityManager->remove($result);
}
Run Code Online (Sandbox Code Playgroud)

一定要打电话

$this->entityManager->flush();
Run Code Online (Sandbox Code Playgroud)

在您的应用程序中的适当位置(通常是控制器).

  • 第三件事 - 这很容易出现竞争条件. (3认同)
  • 仅需提及两件事。1.这可能非常昂贵。2.不敢在控制器中加入这样的逻辑! (2认同)
  • 构建删除查询的全部意义在于,您不必对要删除的所有对象进行水合,并在它们上循环。因此,这可能会非常昂贵,具体取决于您尝试删除的对象数量... (2认同)

小智 5

最好使用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();
Run Code Online (Sandbox Code Playgroud)
  • 好处:运行速度更快,无需迭代
  • 缺点:您无法加入preRemove

对于激烈的“放置在哪里”的辩论,如果愿意,可以将其放在控制器中。这完全取决于您。但是,如果您将代码放入专用的学说存储库类中,那么将来对您可能会更有用。它应该很容易做,并且易于更改/维护。