原则 2 DQL:如何按鉴别器列 (STI) 进行分组

edi*_*igu 5 orm dql doctrine-orm

我有以下 Doctrine 2 STI 车辆实体,该实体有两个名为“汽车”和“自行车”的子类,需要按车辆类型对车辆表中的项目进行计数。(例如;表格摘要:3 辆汽车、5 辆自行车..)

/**
 * @ORM\Entity
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="type", type="string")
 * @ORM\DiscriminatorMap({"V" = "Vehicle", "C" = "CarEntity", "B" = "BikeEntity"})
 * @ORM\Table(name="vehicles", uniqueConstraints={@ORM\UniqueConstraint(name="discr_type_name",columns={"type","name"})})
 */
class Vehicle {
...
}
Run Code Online (Sandbox Code Playgroud)

因此,我尝试执行以下 DQL 查询,但没有一个起作用:

SELECT v, TYPE(v) as vtype, count(v.id) as cnt FROM Vehicle v GROUP BY TYPE(v);
SELECT v, count(v.id) as cnt, TYPE(v) as vtype FROM Vehicle v GROUP BY vtype;
SELECT v, count(v.id) as cnt, TYPE(v) as vtype FROM Vehicle v GROUP BY TYPE(vtype);
Run Code Online (Sandbox Code Playgroud)

查询异常:

[Syntax Error] line 0, col 10: Error: Expected known function, got 'TYPE'
Run Code Online (Sandbox Code Playgroud)

另一个:

[Semantical Error] line 0, col 83 near 'TYPE()': Error: Cannot group by undefined identification or result variable
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?(学说版本为2.3)

Jan*_*lan 1

您可以实现自己的 DQL 函数。网络上有一些可行的解决方案,例如: https: //gist.github.com/jasonhofer/8420677

我使用了该代码并对其进行了一些修改:

<?php

use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\QueryException;
use Doctrine\ORM\Query\SqlWalker;

/**
 * Provides a way to access an entity's discriminator field in DQL
 * queries.
 *
 * Assuming the same "Person" entity from Doctrine's documentation on
 * Inheritance Mapping, which has a discriminator field named "discr":
 *
 * Using the TYPE() function, DQL will interpret this:
 *
 * <pre>'SELECT TYPE(p) FROM Person p'</pre>
 *
 * as if you had written this:
 *
 * <pre>'SELECT p.discr FROM Person p'</pre>
 *
 * This conversion happens at the SQL level, so the ORM is no longer
 * part of the picture at that point.
 *
 * Normally, if you try to access the discriminator field in a DQL
 * Query, Doctrine will complain that the field does not exist on the
 * entity. This makes sense from an ORM point-of-view, but having
 * access to the discriminator field allows us to, for example:
 *
 * - get the type when we only have an ID
 * - query within a subset of all the available types
 */
class TypeFunction extends FunctionNode
{
    public string $dqlAlias;

    /**
     * @throws QueryException
     */
    public function getSql(SqlWalker $sqlWalker): string
    {
        $qComp = $sqlWalker->getQueryComponent($this->dqlAlias);

        /** @var ClassMetadataInfo $class */
        $class = $qComp['metadata'];
        $tableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $this->dqlAlias);

        if (!isset($class->discriminatorColumn['name'])) {
            throw QueryException::semanticalError(
                'TYPE() only supports entities with a discriminator column.'
            );
        }

        return $tableAlias.'.'.$class->discriminatorColumn['name'];
    }

    /**
     * @throws QueryException
     */
    public function parse(Parser $parser): void
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);

        $this->dqlAlias = $parser->IdentificationVariable();

        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }
}
Run Code Online (Sandbox Code Playgroud)

之后,您必须按照Doctrine 手册中的描述注册自定义函数。如果您使用 Symfony,请转到此处。

这使您能够选择鉴别器列的值并稍后在查询中使用它,并且适用于选择、排序和分组。

我的工作片段是这样的:

$queryBuilder
    ->select('COUNT(DISTINCT entity) AS count, TYPE(entity) AS type')
    ->groupBy('type')
;
Run Code Online (Sandbox Code Playgroud)

专业提示:如果您不想type在结果数据中包含 ,您可以使用SELECT TYPE(entity) AS HIDDEN type