使用 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 子句的主要内容,如果未能解决你的问题,请参考以下文章
将 Codeigniter 2 与 Doctrine ORM 2 < PHP v5.2 一起使用
使用 Doctrine ORM 的*** EXISTS 查询