使用 PHP Doctrine ORM 的复杂 WHERE 子句

Posted

技术标签:

【中文标题】使用 PHP Doctrine ORM 的复杂 WHERE 子句【英文标题】:Complex WHERE clauses using the PHP Doctrine ORM 【发布时间】:2010-11-06 04:24:15 【问题描述】:

我正在使用 php Doctrine ORM 来构建我的查询。但是,我似乎不太明白如何使用 DQL(Doctrine Query Language)编写以下 WHERE 子句:

WHERE name='ABC' AND (category1 = 'X' OR category2 = 'X' OR category3 = 'X') 
AND price > 10

如何指定括号的位置?

我目前的 PHP 代码是这样的:

->where('name = ?', 'ABC')
->andWhere('category1 = ?', 'X')
->orWhere('category2 = ?', 'X')
->orWhere('category3 = ?', 'X')
->andWhere('price > ?', 10)

但这会产生类似的东西

WHERE name='ABC' AND category1 = 'X' OR category2 = 'X' OR category3 = 'X' 
AND price > 10

由于操作顺序,它不会返回预期的结果。

另外,“where”、“andWhere”和“addWhere”方法有区别吗?

更新 好的,看起来你不能使用 DQL 进行复杂的查询,所以我一直在尝试手动编写 SQL 并使用 andWhere() 方法来添加它。但是,我正在使用 WHERE..IN 并且 Doctrine 似乎正在剥离我的括号:

$q->andWhere("(category1 IN $subcategory_in_clause
            OR category2 IN $subcategory_in_clause 
            OR category3 IN $subcategory_in_clause)");

【问题讨论】:

另一个解决方案可以在这里找到***.com/a/7720723/251735 【参考方案1】:

根据我的经验,每个复杂的 where 函数都分组在括号内(我使用的是 Doctrine 1.2.1)。

$q->where('name = ?', 'ABC')
  ->andWhere('category1 = ? OR category2 = ? OR category3 = ?', array('X', 'X', 'X'))
  ->andWhere('price < ?', 10)

产生以下 SQL:

WHERE name = 'ABC' 
  AND (category1 = 'X' OR category2 = 'X' OR category3 = 'X')
  AND price < 10

【讨论】:

正是我想要的!【参考方案2】:

如@Jekis 所述,可以在doctrine 2 - query builder conditional queries... If statements? 找到正确的方法。下面是如何使用表达式生成器来解决这个问题,就像在@anushr 的示例中一样。

$qb->where($qb->expr()->eq('name', ':name'))
  ->andWhere(
    $qb->expr()->orX(
      $qb->expr()->eq('category1', ':category1'),
      $qb->expr()->eq('category2', ':category2'),
      $qb->expr()->eq('category3', ':category3')
  )
  ->andWhere($qb->expr()->lt('price', ':price')
  ->setParameter('name', 'ABC')
  ->setParameter('category1', 'X')
  ->setParameter('category2', 'X')
  ->setParameter('category3', 'X')
  ->setParameter('price', 10);

【讨论】:

这正是我讨厌 Doctrine 的原因。这是无法阅读和理解的。 你也可以这样做: $ors = $qb->expr()->orX(); $ors->add($qb->expr()->like('firstName', $qb->expr()->literal("%john%"))); $ors->add($qb->expr()->like('lastName', $qb->expr()->literal("%john%"))); $qb->andWhere($ors); 或者您可以跳过所有这些噪音并将 DQL 字符串连接在一起...只要确保您不会对 SQL 注入开放。【参考方案3】:

由于您似乎无法使用 DQL 进行复杂查询,因此我编写了以下 SQL 以传递给 andWhere() 方法:

$q->andWhere("(category1 IN $subcategory_in_clause
OR category2 IN $subcategory_in_clause 
OR category3 IN $subcategory_in_clause) AND TRUE");

注意“AND TRUE”,这是一个 hack,以便解析器不会忽略外括号。

【讨论】:

我认为 anushr 的解决方案要好得多。没有黑客攻击和使用准备好的语句。【参考方案4】:

andWhere 可以概括为:Previous added Condition(s) Aware WHERE 语句

您可以安全地使用 andWhere 代替 where。 (它引入了非常小的开销,在下面的第二个列表项中进行了说明。)

andWhere 的实现是:(Doctrine 1.2.3)

public function andWhere($where, $params = array())

    if (is_array($params)) 
        $this->_params['where'] = array_merge($this->_params['where'], $params);
     else 
        $this->_params['where'][] = $params;
    

    if ($this->_hasDqlQueryPart('where')) 
        $this->_addDqlQueryPart('where', 'AND', true);
    

    return $this->_addDqlQueryPart('where', $where, true);

可以读作,

    工艺参数 将 AND 语句附加到查询的 where 部分,如果之前添加了另一个 where 语句 附加条件

【讨论】:

【参考方案5】:

至于 where、andwhere 和 addwhere 之间的区别,我认为与我上次阅读源代码时没有显着差异。但是,我鼓励您阅读 Doctrine 源代码。这真的很简单,并且有助于填补文档中的漏洞(有很多)。至于复杂的 where 语句,我自己也想知道,但还没有需要。

【讨论】:

【参考方案6】:

根据我的经验,我有时会发现:

$q->andWhere("(category1 IN $subcategory_in_clause
            OR category2 IN $subcategory_in_clause 
            OR category3 IN $subcategory_in_clause)");

$q->andWhere("(category1 IN $subcategory_in_clause OR category2 IN $subcategory_in_clause OR category3 IN $subcategory_in_clause)");

第一个语句写了 3 行,第二个语句只写了一行。我不相信,但有区别!

【讨论】:

【参考方案7】:
$q->andWhere("category1 IN ( $subcategory_in_clause )
              OR category2 IN ( $subcategory_in_clause )
              OR category3 IN ( $subcategory_in_clause )");

您是否愿意尝试这个变体,不确定它是否有效,但值得一试

【讨论】:

以上是关于使用 PHP Doctrine ORM 的复杂 WHERE 子句的主要内容,如果未能解决你的问题,请参考以下文章

PHP ORM:Doctrine vs. Propel

将 Codeigniter 2 与 Doctrine ORM 2 < PHP v5.2 一起使用

从 orm.xml Doctrine 生成 php 实体

使用 Doctrine ORM 的*** EXISTS 查询

如何使用ApcuCache与Symfony,Doctrine ORM和DoctrineCacheBundle

使用 Doctrine orm symfony 创建新数据库时出错