以下示例显示了代码示例的一些摘录。调用 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;
    }
    

    最佳答案

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

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

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

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

    /**
     * @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;
    }
    

    关于php - 在 Doctrine DBAL 中重用 QueryBuilder,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40069020/

    10-12 01:30