我正在尝试获取 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 中
您应该能够添加自己的函数来实现此功能。
课程看起来像这样:
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
将不会出现在结果中(仅用于排序)。
根据 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
在不更改数据类型的情况下尝试一下这个
select (entity1 * 1) as display_value, entity1 as return_value
from Table_Name
order by 1 asc;
认为在这种情况下最好使用一些额外的功能(不要试图“规避”他们的功能)。例如。为
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
不确定这是否有效,但要访问实体 ID,您需要 IDENTITY() DQL 函数。试试这个:
SELECT entity1 FROM Namespace\Bla\MyEntity ORDER BY IDENTITY(entity1)
我想你想在
entity1
之前订购。如果您的entity1数据类型是整数,则无需将其更改为整数,否则您应该这样做。下面是你的查询。试试这个。
select entity1,cast(entity1 as integer) as order_id from Table_Name order by 1 asc;
我昨天刚刚在自己的代码中做了类似的事情。我能够做到:
select cast(entity1 as int) as OrderID
from yourtablename
where yourconditions
我实际上必须先将我的货币转换为货币,然后再转换为整数,但如果你没有小数,则不应该遇到这个问题。您还可以尝试将其转换为数字或使用转换而不是转换,但在这种情况下转换更好。
如果 OrderID 中已具有相同的值,为什么还需要实体 1 作为列?