Атрибуты CASTING для упорядочивания в DQL-запросе Doctrine2 - PullRequest
18 голосов
/ 13 сентября 2011

Я пытаюсь получить сущностей Doctrine2 , упорядоченных по их идентификатору, который, очевидно, является строкой, хотя он содержит только числа.Так что я хотел бы сделать что-то вроде этого:

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

Есть ли способ сделать что-то подобное в Doctrine2 ?Или, что было бы лучшим способом получить мой результат, если я не могу изменить тип идентификатора ( из-за требований клиента, конечно )?


Внимание : я не спрашиваю код SQL, я прошу решение для Doctrine2, предпочтительно на DQL

Ответы [ 7 ]

25 голосов
/ 07 мая 2014

Вы должны иметь возможность добавить собственную функцию для реализации этой функции.

Класс будет выглядеть примерно так:

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', 'MyProject\Query\CastAsInteger');

Тогда вы можете использовать его:

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

PS: добавив ключевое слово HIDDEN, псевдоним orderId не будет в результатах (и используется только для упорядочивания).

6 голосов
/ 07 сентября 2017

Основываясь на ответе Джаспера Н. Брауэра, это немного улучшенное решение:

<?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 голосов
/ 07 декабря 2012

Попробуйте это без изменения типа данных

  select (entity1 * 1) as display_value, entity1 as return_value 
      from Table_Name
     order by 1 asc;
0 голосов
/ 25 мая 2019

Думаю, в таких случаях лучше использовать какой-нибудь дополнительный функционал (не пытаясь "обойти" их). Например. отличное решение, добавляющее почти все необходимые (не поддерживаемые из коробки) вещи для Doctrine 2 - DoctrineExtensions от beberlei (github). С его помощью можно напрямую использовать CAST -статмент, как в случае с OP:

(«Пример Symfony») Например, в вашем 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 голосов
/ 31 октября 2013

Не уверен, что это работает, но для доступа к идентификатору сущности вам нужна функция DQL IDENTITY (). Попробуйте это:

SELECT entity1  FROM Namespace\Bla\MyEntity  ORDER BY IDENTITY(entity1)
0 голосов
/ 07 декабря 2012

Я только что сделал нечто подобное в своем собственном коде вчера. Я смог сделать:

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

Я должен был на самом деле разыграть мой как деньги, а затем int, но если у вас нет десятичной дроби, у вас не должно быть этой проблемы. Вы также можете попробовать выполнить приведение числа или использовать преобразование вместо преобразования, но преобразование лучше в этой ситуации.

Зачем вам нужно entity1 в качестве столбца, если у вас уже есть то же значение в OrderID?

0 голосов
/ 07 декабря 2012

Я думаю, вы хотите заказать по entity1.если ваш тип данных entity1 является целым числом, нет необходимости менять его на целое или если это не так, то вам следует это сделать.ниже запрос для вас. попробуйте этот.

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