【问题标题】:CASTING attributes for Ordering on a Doctrine2 DQL Query在 Doctrine2 DQL 查询上进行排序的 CASTING 属性
【发布时间】:2011-11-16 08:20:52
【问题描述】:

我正在尝试获取 Doctrine2 实体,按他们的 ID 排序,这显然是一个字符串,即使它只包含数字。 所以我想做的是这样的:

SELECT entity1, cast (entity1.id AS integer) AS orderId
FROM Namespace\Bla\MyEntity 
ORDER BY orderId

有没有办法在 Doctrine2 中做这样的事情? 或者,如果我无法更改 id 的类型(当然是由于客户要求),那么获得我的结果的最佳做法是什么?


注意:我不是在问 SQL 代码,我是在问一个 Doctrine2 解决方案,最好是在 DQL 中

【问题讨论】:

  • 我认为您在第 13 行缺少(

标签: casting doctrine-orm type-conversion dql


【解决方案1】:

你应该可以add your own function来实现这个功能。

这个类看起来像这样:

namespace MyProject\Query;

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

class CastAsInteger extends FunctionNode
{
    public $stringPrimary;

    public function getSql(SqlWalker $sqlWalker)
    {
        return 'CAST(' . $this->stringPrimary->dispatch($sqlWalker) . ' AS 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);
    }
}

你需要注册你的函数:

$config = $em->getConfiguration();
$config->addCustomNumericFunction('INT', CastAsInteger::class);

然后就可以使用了:

SELECT e, INT(e.id) AS HIDDEN orderId
FROM Namespace\Bla\MyEntity e
ORDER BY orderId

PS:通过添加HIDDEN 关键字,别名orderId 将不会出现在结果中(并且仅用于排序)。

【讨论】:

  • 在我自己的函数中,我有一个 SingleValuedPathExpressionu.group 并希望使用实际的 Expression 对象将其“包装”在 "CAST(" SingleValuedPathExpression " AS DECIMAL(10,2))" 中......我该怎么做? CAST ...在手工构建时会是什么样的表达?
  • 好吧,没关系;我使用了一个自定义表达式并修改了它的->dispatch() 方法以满足我的需要。清洁如预期。教义真棒。 :)
  • 如果目标数据库是MySql,这行不行:return 'CAST(' . $this->stringPrimary->dispatch($sqlWalker) . ' AS integer)';试试这个:return 'CAST(' . $this->stringPrimary->dispatch($sqlWalker) . ' AS SIGNED)';
  • 只是为了在 Symfony 中记录,您将寄存器部分放在 config.yml
【解决方案2】:

基于 Jasper N. Brouwer 的回答,这是一个稍微增强的解决方案:

<?php
namespace MyProject\Query;

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

class Cast extends FunctionNode
{
    /** @var \Doctrine\ORM\Query\AST\PathExpression */
    protected $first;
    /** @var string */
    protected $second;
    /**
     * @param SqlWalker $sqlWalker
     *
     * @return string
     */
    public function getSql(SqlWalker $sqlWalker)
    {
        return sprintf("CAST(%s AS %s)",
            $this->first->dispatch($sqlWalker),
            $this->second
            );
    }


    /**
     * @param Parser $parser
     *
     * @return void
     */
    public function parse(Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);
        $this->first = $parser->ArithmeticPrimary();
        $parser->match(Lexer::T_AS);
        $parser->match(Lexer::T_IDENTIFIER);
        $this->second = $parser->getLexer()->token['value'];
        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }
}

现在应该可以像这样编写 DQL:

SELECT e, CAST(e.id AS integer) AS HIDDEN orderId FROM Namespace\Bla\MyEntity e ORDER BY orderId

【讨论】:

    【解决方案3】:

    认为在这种情况下最好使用一些额外的功能(而不是试图“规避”他们的功能)。例如。为Doctrine 2 添加几乎所有必要(不支持)的东西的优秀解决方案是DoctrineExtensions by beberlei (github)。有了它,就可以直接使用CAST-statement,就像在 OP 的情况下一样:

    ("Symfony-example") 例如在你的config.xml 添加行:

    orm:
        ..
        entity_managers:
                ....
                dql:
                    ....
                    string_functions:
                        CAST: DoctrineExtensions\Query\Mysql\Cast
    

    然后你可以像这样使用它:

     SELECT entity1, CAST(entity1.id AS integer) AS orderId
     FROM Namespace\Bla\MyEntity 
     ORDER BY orderId
    

    【讨论】:

      【解决方案4】:

      不确定这是否有效,但要访问实体 ID,您需要 IDENTITY() DQL 函数。试试这个:

      SELECT entity1  FROM Namespace\Bla\MyEntity  ORDER BY IDENTITY(entity1)
      

      【讨论】:

        【解决方案5】:

        我昨天刚刚在自己的代码中做了类似的事情。我能够做到:

        select cast(entity1 as int) as OrderID
        from yourtablename
        where yourconditions
        

        我必须将我的实际转换为 money 然后 int,但如果你没有小数,你不应该有这个问题。您也可以尝试转换为数字或使用转换而不是转换,但在这种情况下转换更好。

        如果 OrderID 中已经有相同的值,为什么还需要 entity1 作为列?

        【讨论】:

        • 你知道我使用的是doctrine2 DQL而不是MySQL吗?
        • 我没有意识到这一点,我使用的是用于 sqlserver 的 sql,而不是 mysql,但它们非常相似。
        【解决方案6】:

        在不改变数据类型的情况下试试这个

          select (entity1 * 1) as display_value, entity1 as return_value 
              from Table_Name
             order by 1 asc;
        

        【讨论】:

        • 你知道我使用的是doctrine2 DQL而不是MySQL吗?
        【解决方案7】:

        我想你想通过entity1 订购。如果您的 entity1 数据类型是整数,则无需将其更改为整数,否则您应该这样做。下面是你的查询。试试这个。

        select entity1,cast(entity1 as integer) as order_id from Table_Name order by 1 asc;
        

        【讨论】:

        • 如前所述,由于客户要求,我无法更改
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-12
        • 1970-01-01
        • 2015-01-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多