Doctrine QueryBuilder 删除连接

问题描述 投票:0回答:5

我正在尝试使用 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

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

php mysql doctrine-orm query-builder
5个回答
22
投票

使用 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

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


17
投票

看起来DQL不支持这种删除语句。 Doctrine 文档中的 BNF 表明

delete_statement
必须采用

形式
delete_clause [where_clause]

其中

delete_clause
定义为:

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

因此我可以提供模式和 where 子句,但没有连接。


4
投票

实现此目的的一种方法可能是首先使用联接查询要删除的实体:

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

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


0
投票

@chris-hanson 已经指出 Doctrine 不支持带有连接的删除语句(因为它不是标准 SQL)。

但是我找到了一种解决方案,通过使用带有子查询的删除语句,可以通过一个查询实现类似的效果。

$query = $this->getEntityManager()->createQuery(<<<DQL
    DELETE FROM \SANUS\Entity\ProductHolePattern outer_php
    WHERE outer_php.id IN (
        SELECT php.id FROM \SANUS\Entity\ProductHolePattern php
        INNER JOIN php.holePattern hp
        INNER JOIN hp.holePatternType hpt
        WHERE hpt.slug = :slug AND php.product = :product
    )
DQL);
$query->setParameter('slug', 'universal');
$query->setParameter('product', $this->id);
$query->execute();

@kshishkin 的解决方案相比,优点是减少到一个查询,并且您不必将第一个查询的结果作为参数传递给第二个查询。

如果您从第一次查询中获得大量 ID,则后者可能会出现问题,这些 ID 必须从数据库服务器传输到 PHP,由 PHP 处理,然后传输回服务器。

如果数据库可以在内部处理这些 ID,速度会快得多。

查询也可以由查询构建器生成,但是用它构建子查询非常麻烦;-)(如果您需要知道如何做到这一点,您可以查看这里)。


-6
投票

在 Symfony2 上请尝试:

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

$em->flush();

仅此而已。

© www.soinside.com 2019 - 2024. All rights reserved.