如何在 Doctrine 2 中对本机查询进行分页?
Posted
技术标签:
【中文标题】如何在 Doctrine 2 中对本机查询进行分页?【英文标题】:How to paginate a native query in Doctrine 2? 【发布时间】:2013-01-22 16:05:11 【问题描述】:Doctrine 2 具有 Doctrine\ORM\Tools\Pagination\Paginator 类,可用于对普通 DQL 查询进行分页。
但是,如果我将本机查询传递给它,我会收到此错误:
Catchable fatal error: Argument 1 passed to Doctrine\ORM\Tools\Pagination\Paginator::cloneQuery() must be an instance of Doctrine\ORM\Query, instance of Doctrine\ORM\NativeQuery given
我尝试在 cloneQuery 方法中从分页器类中删除类型提示,但这只会产生更多错误,因为分页器类的其他位期望在 Query 中找到的方法不在 NativeQuery 中。
是否有任何简单的方法可以对原生查询进行分页,而无需构建新的分页器类或将数据库中的每一行都提取到数组中?
【问题讨论】:
我不认为有这样的东西 - 至少我还没有找到任何东西。 【参考方案1】:我自己制作了与 Zend_Paginator 兼容的分页器适配器类。
可能不是最灵活的,因为它依赖于在查询开头附近有一个“FROM”(请参阅 count() 方法),但它是一个相对快速和简单的解决方法。
/**
* Paginate native doctrine 2 queries
*/
class NativePaginator implements Zend_Paginator_Adapter_Interface
/**
* @var Doctrine\ORM\NativeQuery
*/
protected $query;
protected $count;
/**
* @param Doctrine\ORM\NativeQuery $query
*/
public function __construct($query)
$this->query = $query;
/**
* Returns the total number of rows in the result set.
*
* @return integer
*/
public function count()
if(!$this->count)
//change to a count query by changing the bit before the FROM
$sql = explode(' FROM ', $this->query->getSql());
$sql[0] = 'SELECT COUNT(*)';
$sql = implode(' FROM ', $sql);
$db = $this->query->getEntityManager()->getConnection();
$this->count = (int) $db->fetchColumn($sql, $this->query->getParameters());
return $this->count;
/**
* Returns an collection of items for a page.
*
* @param integer $offset Page offset
* @param integer $itemCountPerPage Number of items per page
* @return array
*/
public function getItems($offset, $itemCountPerPage)
$cloneQuery = clone $this->query;
$cloneQuery->setParameters($this->query->getParameters(), $this->query->getParameterTypes());
foreach($this->query->getHints() as $name => $value)
$cloneQuery->setHint($name, $value);
//add on limit and offset
$sql = $cloneQuery->getSQL();
$sql .= " LIMIT $itemCountPerPage OFFSET $offset";
$cloneQuery->setSQL($sql);
return $cloneQuery->getResult();
【讨论】:
我不确定分页器是如何实现的,但是在不转义的情况下直接将参数传递给 SQL 时要小心 SQLi。在这种情况下,转换为 int 就足够了【参考方案2】:public function countTotalRecords($query, string $primaryKey = '*'): int
if ($query instanceof QueryBuilder)
$paginator = new Paginator($query->getQuery());
return count($paginator);
else if ($query instanceof NativeQuery)
$rsm = new ResultSetMappingBuilder($query->getEntityManager());
$rsm->addScalarResult('count', 'count');
$sqlCount = "select count(".$primaryKey.") as count from (" . $query->getSQL() . ") as item";
$count = $query->getEntityManager()->createNativeQuery($sqlCount, $rsm);
if ($query->getParameter('limit'))
$query->setParameter('limit', null);
$count->setParameters($query->getParameters());
return (int)$count->getSingleScalarResult();
return 0;
【讨论】:
您能否说明一下这是如何解决问题的? 是一个示例,说明如何在本机查询或查询构建器中返回总记录数,偏移量的每次更改都会返回剩余记录数【参考方案3】:如果你有一个 dbal query builder
来构建
$yourDbalQueryBuilder = $connection->createQueryBuilder();
那么你可以使用:
$yourDbalQueryBuilder->setFirstResult(0)
->setMaxResults(100000000)
->execute()
->rowCount();
【讨论】:
以上是关于如何在 Doctrine 2 中对本机查询进行分页?的主要内容,如果未能解决你的问题,请参考以下文章
Symfony2 Doctrine 错误:无法计算使用 HAVING 子句的查询。使用输出步行器进行分页