在 Doctrine DBAL 中重用 QueryBuilder

Posted

技术标签:

【中文标题】在 Doctrine DBAL 中重用 QueryBuilder【英文标题】:Reusing QueryBuilder in Doctrine DBAL 【发布时间】:2017-02-25 09:53:30 【问题描述】:

以下示例显示了一些代码示例的摘录。在那里调用 Doctrine DBAL 的 QueryBuilder 两次 - 一次用于执行 SELECT(*) 语句,然后在执行 COUNT(*) 语句之前。

表格、条件、排序顺序和结果限制等常用设置应用于重复使用的QueryBuilder 对象。

问题

隐式重用$queryBuilder 是否有缺点,如示例中所示? 是否建议只复制粘贴单独 QueryBuilder 实例的代码? 使用clone $queryBuilder有副作用吗?

代码示例

/**
 * @param array $arguments
 * @return string
 */
private function getOutput(array $arguments)

    /** @var \Doctrine\DBAL\Connection $connection */
    $connection = $this->getConnection();

    $queryBuilder = $connection
        ->createQueryBuilder()
        ->from('some_table')
        ->orderBy('sorting')
        ->setMaxResults(100);

    $condition = $queryBuilder->expr()->andX();
    // ... build conditions
    $queryBuilder->where($condition);

    $count = $queryBuilder->select('COUNT(*)')->execute()->fetchColumn(0);
    if ($count === 0) 
        return 'There is nothing to show';
    
    if ($count > 100) 
        $output = 'Showing first 100 results only:' . php_EOL;
     else 
        $output = 'Showing all results:' . PHP_EOL;
    

    // implicitly reusing previously defined settings
    // (table, where, orderBy & maxResults)
    $statement = $queryBuilder->select('*')->execute();
    foreach ($statement as $item) 
        $output .= $this->renderItem($item) . PHP_EOL;
    

    return $output;

【问题讨论】:

【参考方案1】:

Doctrine DBAL 中的 QueryBuilder 可用于动态定义 SQL 查询并再次覆盖查询部分。因此,通常在同一个 QueryBuilder 实例上调用 select() 方法两次会覆盖之前的 select 查询部分。构建器内部有一个干净或脏状态的属性——一旦状态是脏的,就必须重新创建 SQL 字符串。例如,覆盖查询部分会触发脏状态。

因此,从简单的技术角度来看,一般来说重用 QueryBuilder 是可能的并且很好。但是,QueryBuilder 不会验证跨数据库的特定逻辑。这意味着,在执行语句时必须手动清除多余的查询部分以避免查询失败。

更好的方法是将构建查询的过程分成不同的逻辑类方法 - 一个分配通用查询约束,其他分配用于特定上下文(例如计算结果与排序和限制结果集)。最后,初始代码示例可能如下所示:

引入了两种额外的方法来丰富查询

/**
 * @param QueryBuilder $queryBuilder
 */
private function addConstraints(QueryBuilder $queryBuilder)

    $condition = $queryBuilder->expr()->andX();
    // ... build conditions
    $queryBuilder->where($condition);


/**
 * @param QueryBuilder $queryBuilder
 */
private function addResultSettings(QueryBuilder $queryBuilder)

    $queryBuilder
        ->orderBy('sorting')
        ->setMaxResults(100);

现在有两个 QueryBuilder 实例,但是查询基本上是在前面显示的两个新方法中定义的。

/**
 * @param array $arguments
 * @return string
 */
private function getOutput(array $arguments)

    /** @var \Doctrine\DBAL\Connection $connection */
    $connection = $this->getConnection();

    // first query builder instance for counting records
    $queryBuilder = $connection->createQueryBuilder()->from('some_table');
    $this->addConstraints($queryBuilder);
    $statement = $queryBuilder->select('COUNT(*)')->execute();

    $count = $statement->fetchColumn(0);
    if ($count === 0) 
        return 'There is nothing to show';
    
    if ($count > 100) 
        $output = 'Showing first 100 results only:' . PHP_EOL;
     else 
        $output = 'Showing all results:' . PHP_EOL;
    

    // second query builder instance to actually retrieve result set
    $queryBuilder = $connection->createQueryBuilder()->from('some_table');
    $this->addConstraints($queryBuilder);
    $this->addResultSettings($queryBuilder);
    $statement = $queryBuilder->select('*')->execute();

    foreach ($statement as $item) 
        $output .= $this->renderItem($item) . PHP_EOL;
    

    return $output;

【讨论】:

以上是关于在 Doctrine DBAL 中重用 QueryBuilder的主要内容,如果未能解决你的问题,请参考以下文章

学说:ORM QueryBuilder 或 DBAL QueryBuilder

在 Symfony 中使用 Doctrine 的 DBAL 检索布尔值

在作曲家 laravel 上安装依赖项(doctrine/dbal)

如何使用 Doctrine DBAL?

PostgreSQL 咨询锁不适用于 Doctrine 的 DBAL

更新或插入方法中的 Doctrine 2 DBAL 表达式