php - 在 Doctrine 2 ORDER BY 中使用 DQL 函数

标签 php mysql symfony doctrine-orm sql-order-by

我正在使用 MySQL 数据库在 Symfony 2.3 和 Doctrine 2.4 中做一个项目。

我有一个 FieldValue 实体(简化):

class FieldValue
{
    /**
     * The ID
     *
     * @var integer
     */
    protected $fieldValueId;

    /**
     * Id of associated Field entity
     *
     * @var integer
     */
    protected $fieldId;

    /**
     * Id of associated user
     *
     * @var integer
     */
    protected $userId;

    /**
     * The value for the Field that user provided
     *
     * @var string
     */
    protected $userValue;

    /**
     * @var \MyProjectBundle\Entity\Field
     */
    protected $field;

    /**
     * @var \MyProjectBundle\Entity\User
     */
    protected $user;

我遇到的问题是,虽然 $userValue 在我的数据库中是 LONGTEXT,但它可以表示实际文本值、日期或数字,具体取决于类型字段

Field可以动态添加。在向任何用户添加一个后,每个其他用户也可以为该字段填充它自己的值。

在查询数据库时,我使用 orderBy 对特定列进行排序,该列也可以是这些字段之一。在这种情况下,我需要对 $userValue 进行排序。当我需要将数字字段排序为数字而不是字符串时,这是有问题的(在这种情况下,“123”小于“9”...)。

它的解决方案(我认为)是 CAST $sort,所以我会得到像这样的 SQL:

ORDER BY CAST(age AS SIGNED INTEGER) ASC

由于 Doctrine 没有为此内置的 DQL 函数,我冒昧地将其作为 INT DQL 函数添加到我的项目中(感谢 Jasper N. Brouwer ):

class CastAsInteger extends FunctionNode
{
    public $stringPrimary;

    public function getSql(SqlWalker $sqlWalker)
    {
        return 'CAST(' . $this->stringPrimary->dispatch($sqlWalker) . ' AS SIGNED INTEGER)';
    }

    public function parse(Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);

        $this->stringPrimary = $parser->StringPrimary();

        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }
}

很高兴自己找到了一个简单的解决方案,我这样做了:

$sort = "INT(".$sort.")";

$queryBuilder->orderBy($sort, $dir);

产生了预期的 DQL:

ORDER BY INT(age) ASC

但也产生了异常:

在呈现模板期间抛出异常(“[语法错误] 第 0 行,第 12272 列:错误:预期的字符串结尾,在 MyProject 中得到 '('”...)

所以我试图找出发生了什么,并在 Doctrine\ORM\Query\Parser.php 中对此进行了研究:

/**
     * OrderByItem ::= (
     *      SimpleArithmeticExpression | SingleValuedPathExpression |
     *      ScalarExpression | ResultVariable
     * ) ["ASC" | "DESC"]
     *
     * @return \Doctrine\ORM\Query\AST\OrderByItem
     */
    public function OrderByItem()
    {
        ...
    }

这是否意味着不可能在 ORDER BY 中使用 DQL 函数? 如果是这种情况 - 是否有任何其他方法可以实现这一目标?

更新

我实际上已经在我的选择查询中使用了 INT,在 CASE WHEN 中:

if ($field->getFieldType() == 'number') {
    $valueThen = "INT(".$valueThen.")";
}

$newFieldAlias = array("
    (CASE
        WHEN ...
        THEN ".$valueThen."
        ELSE ...
        END
    ) as ".$field->getFieldKey());

稍后将 $newFieldAlias 添加到查询中。

没有任何改变...

更新 2

即使我在查询中添加了一个额外的选择,也会导致这个 DQL:

SELECT age, INT(age) as int_age

然后这样排序:

ORDER BY int_age ASC

我仍然没有得到正确的结果。

我已经从 $query->getResult() 检查了 var_dump,这是我得到的:

'age' => string '57' (length=2)      
'int_age' => string '57' (length=2)

喜欢CAST无所谓。我是无知的...

最佳答案

Doctrine DQL 不接受函数作为排序标准,但它确实接受“结果变量”。这意味着您可以执行以下操作:

$q = $this->createQueryBuilder('e')
    ->addSelect('INT(age) as HIDDEN int_age')
    ->orderBy('int_age');

关于php - 在 Doctrine 2 ORDER BY 中使用 DQL 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24765826/

相关文章:

javascript - 来自 php 文件的 xampp 脚本不会转移到 html 文件

php - Android/php : Using PDO to retrieve a set of results using 'LIKE' , 并解析为 JSON

相当于 Ruby 赋值习语的 PHP

php - Twig 和 Symfony2 中的自定义反式过滤器

php - 将Mysql查询结果传递给javascript,然后使用原始变量调用函数。

php - Wordpress 数据库类 - MySQL Type Bit

php - 最佳实践 - 使用 Symfony 2 删除链接

mysql - Symfony2,Doctrine和MySQL:如何生成发票号

php - kernel.request 事件 setResponse 到 RedirectResponse 不工作

php - 计算数据库列文本值 - Laravel