Атрибуты CASTING для заказа в запросе Doctrine2 DQL

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

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

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


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


person Andresch Serj    schedule 13.09.2011    source источник
comment
Я думаю, вам не хватает ( в строке 13.   -  person DonJuwe    schedule 29.04.2014


Ответы (7)


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

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

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 не будет в результатах (и используется только для упорядочивания).

person Jasper N. Brouwer    schedule 07.05.2014
comment
В моей собственной функции у меня есть SingleValuedPathExpression как u.group, и я хочу обернуть это в "CAST(" SingleValuedPathExpression " AS DECIMAL(10,2))", используя настоящие объекты Expression... как мне это сделать? Каким выражением будет CAST ... при создании его вручную? - person Adrian Föder; 25.01.2015
comment
хорошо, неважно; Я использовал пользовательское выражение и изменил его метод ->dispatch() в соответствии со своими потребностями. Как и ожидалось, чище. Доктрина классная. :) - person Adrian Föder; 25.01.2015
comment
Если целевой базой данных является MySql, эта строка не работает: return 'CAST(' . $this->stringPrimary->dispatch($sqlWalker) . ' AS integer)'; Попробуйте это: return 'CAST(' . $this->stringPrimary->dispatch($sqlWalker) . ' AS SIGNED)'; - person Hokusai; 13.03.2015
comment
Просто для записи в Symfony вы помещаете регистровую часть в config.yml - person Nelson Teixeira; 08.04.2016

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

<?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
person Petr    schedule 07.09.2017

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

  select (entity1 * 1) as display_value, entity1 as return_value 
      from Table_Name
     order by 1 asc;
person Usman YousafZai    schedule 07.12.2012
comment
Вы знаете, что я использую DQL Doctrine2, а не MySQL? - person Andresch Serj; 10.12.2012

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

(«Пример Symfony») в вашем config.xml добавьте строки:

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

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

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

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

SELECT entity1  FROM Namespace\Bla\MyEntity  ORDER BY IDENTITY(entity1)
person derula    schedule 31.10.2013

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

select entity1,cast(entity1 as integer) as order_id from Table_Name order by 1 asc;
person Usman YousafZai    schedule 07.12.2012
comment
Как уже упоминалось, я не могу изменить его из-за требований заказчика. - person Andresch Serj; 07.12.2012

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

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

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

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

person rainhider    schedule 07.12.2012
comment
Вы знаете, что я использую DQL Doctrine2, а не MySQL? - person Andresch Serj; 10.12.2012
comment
Я не знал об этом и использовал sql для sqlserver, а не mysql, но они очень похожи. - person rainhider; 10.12.2012