用于 Doctrine2 DQL 查询排序的 CASTING 属性

问题描述 投票:0回答:7

我正在尝试获取 Doctrine2 Entities,按其 ID 排序,该 ID 显然是一个字符串,尽管它只包含数字。 所以我想做的是这样的:

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

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


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

casting doctrine-orm type-conversion dql
7个回答
40
投票

您应该能够添加自己的函数来实现此功能。

课程看起来像这样:

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
将不会出现在结果中(仅用于排序)。


7
投票

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

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
投票

在不更改数据类型的情况下尝试一下这个

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

1
投票

认为在这种情况下最好使用一些额外的功能(不要试图“规避”他们的功能)。例如。为

Doctrine 2
添加几乎所有必需的(盒子不支持)内容的一个优秀解决方案是 DoctrineExtensions by beberlei (github)。有了它,就可以直接使用
CAST
语句,就像 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

0
投票

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

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

-1
投票

我想你想在

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

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

-3
投票

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

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

我实际上必须先将我的货币转换为货币,然后再转换为整数,但如果你没有小数,则不应该遇到这个问题。您还可以尝试将其转换为数字或使用转换而不是转换,但在这种情况下转换更好。

如果 OrderID 中已具有相同的值,为什么还需要实体 1 作为列?

© www.soinside.com 2019 - 2024. All rights reserved.