【问题标题】:Add extra SELECT expression result to the existing entity向现有实体添加额外的 SELECT 表达式结果
【发布时间】:2018-03-28 19:52:31
【问题描述】:

我有一个项目可以对一家公司进行多方面的评价。下图可以帮助您理解我的数据库中的关系。当然,我已经从方案中删除了在我的问题上下文中不重要的字段。 目前,在Company 实体的存储库类中,我正在使用QueryBuilder 搜索公司并返回\Doctrine\ORM\Tools\Pagination\Paginator 的实例。

以下代码负责获取公司:

public function search(CompanySearchQuery $command): Paginator
{
    $qb = $this->createQueryBuilder('c')
        ->setFirstResult($command->getOffset())
        ->setMaxResults($command->getMaxResults())
        ->orderBy('c.name', 'ASC');

    ... plus extra "where" conditions

    return new Paginator($qb, true);
}

我想知道如何使用QueryBuilderPaginator 将平均分数附加到每家公司。

这是允许我获取所需数据的本机 SQL:

SELECT
  c.id,
  c.name,
  AVG(o2.score) as score
FROM
  company c
LEFT JOIN
  opinion o ON c.id = o.company_id
LEFT JOIN
  opinion_scope o2 ON o.id = o2.opinion_id
GROUP BY
  c.id

我的问题是:是否可以将averageScore 属性添加到Company 类并从QueryBuilder 结果映射它?

我尝试重写我的 SQL 查询以与现有代码一起使用:

$qb = $this->createQueryBuilder('c')
    ->select('c', 'AVG(s.score)')
    ->leftJoin('c.opinions', 'o')
    ->leftJoin('o.scopes', 's')
    ->groupBy('c.id')
    ->setFirstResult($command->getOffset())
    ->setMaxResults($command->getMaxResults())
    ->orderBy('c.name', 'ASC')
;

使用上面的代码,我得到如下数据库异常:

SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #14 of 
SELECT list is not in GROUP BY clause and contains nonaggregated column 
'database.o1_.score' which is not functionally dependent on columns in GROUP BY
clause; this is incompatible with sql_mode=only_full_group_by").

为上述 QueryBuilder 执行的 SQL 查询是:

SELECT 
  DISTINCT id_8 
FROM 
  (
    SELECT 
      DISTINCT id_8, 
      name_9 
    FROM 
      (
        SELECT 
          c0_.updated_at AS updated_at_0, 
          c0_.description AS description_1, 
          c0_.website AS website_2, 
          c0_.email AS email_3, 
          c0_.phone AS phone_4, 
          c0_.street AS street_5, 
          c0_.postal_code AS postal_code_6, 
          c0_.city AS city_7, 
          c0_.id AS id_8, 
          c0_.name AS name_9, 
          c0_.slug AS slug_10, 
          c0_.created_at AS created_at_11, 
          AVG(o1_.score) AS sclr_12, 
          o1_.score AS score_13, 
          o1_.opinion_id AS opinion_id_14, 
          o1_.type_id AS type_id_15 
        FROM 
          company c0_ 
          LEFT JOIN opinion o2_ ON c0_.id = o2_.company_id 
          LEFT JOIN opinion_scope o1_ ON o2_.id = o1_.opinion_id 
        GROUP BY 
          c0_.id
      ) dctrn_result_inner 
    ORDER BY 
      name_9 ASC
  ) dctrn_result 
LIMIT 
  2 OFFSET 0

我不明白 Doctrine 为什么要添加以下片段:

o1_.score AS score_13, 
o1_.opinion_id AS opinion_id_14, 
o1_.type_id AS type_id_15 

【问题讨论】:

    标签: php mysql symfony doctrine-orm


    【解决方案1】:

    问题似乎是您试图从“c”中选择每一列,这是您通过执行两个 LEFT JOIN 得到的表。相反,您需要为 company 表指定一个 from 子句:

    $qb = $this->createQueryBuilder()
        ->select('c', 'AVG(s.score)')
        ->from('company', 'c')
        ->leftJoin('c.opinions', 'o')
        ->leftJoin('o.scopes', 's')
        ->groupBy('c.id')
        ->setFirstResult($command->getOffset())
        ->setMaxResults($command->getMaxResults())
        ->orderBy('c.name', 'ASC')
    ;
    

    这将避免包含 o1.score 是您返回的列,这就是该错误所引用的内容

    【讨论】:

    • 我附加的 SQL 查询在我直接在我的数据库上执行时运行良好,但我在重写它以与 Doctrine Query Builder 一起使用时遇到了问题。
    • 我已经添加了Doctrine生成的SQL查询。
    • @MichałSzczech 实际上我认为这是因为您没有在 SELECT 之后指定 ->from 子句。在这种情况下,'c' 是您在所有 LEFT JOIN 之后得到的结果表,其中将包括它们的列
    • 编辑了我的答案@MichałSzczech
    • \Doctrine\ORM\EntityRepository::createQueryBuilder 方法使用当前存储库中的实体和它的第一个参数的别名添加 from 子句。
    猜你喜欢
    • 2021-09-29
    • 1970-01-01
    • 2011-04-27
    • 1970-01-01
    • 2016-09-14
    • 2017-05-26
    • 1970-01-01
    • 2019-04-17
    • 1970-01-01
    相关资源
    最近更新 更多