【发布时间】:2014-09-06 02:22:00
【问题描述】:
我正在使用 MySQL 数据库在 Symfony 2.3 中使用 Doctrine 2.4 做一个项目。
我有一个 FieldValue 实体(简体):
class FieldValue
{
/**
* The ID
*
* @var integer
*/
protected $fieldValueId;
/**
* Id of associated Field entity
*
* @var integer
*/
protected $fieldId;
/**
* Id of associated user
*
* @var integer
*/
protected $userId;
/**
* The value for the Field that user provided
*
* @var string
*/
protected $userValue;
/**
* @var \MyProjectBundle\Entity\Field
*/
protected $field;
/**
* @var \MyProjectBundle\Entity\User
*/
protected $user;
我遇到的问题是$userValue,虽然它在我的数据库中是LONGTEXT,但可以表示实际文本值、日期或数字,具体取决于Field 的类型。
字段可以动态添加。在向任何用户添加 1 后,每个其他用户也可以为该字段填充它自己的值。
在查询数据库时,我使用 orderBy 对某个列进行排序,该列也可以是这些字段之一。在这种情况下,我需要对$userValue 进行排序。当我需要将数字字段排序为数字而不是字符串时,这是有问题的(在这种情况下,'123' 小于 '9'...)。
它的解决方案(我想)是CAST$sort,所以我会得到类似的SQL:
ORDER BY CAST(age AS SIGNED INTEGER) ASC
由于 Doctrine 没有内置的 DQL 函数,我冒昧地将它作为 INT DQL 函数添加到我的项目中(感谢 Jasper N. Brouwer):
class CastAsInteger extends FunctionNode
{
public $stringPrimary;
public function getSql(SqlWalker $sqlWalker)
{
return 'CAST(' . $this->stringPrimary->dispatch($sqlWalker) . ' AS SIGNED 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);
}
}
很高兴自己找到了一个简单的解决方案,我做到了:
$sort = "INT(".$sort.")";
$queryBuilder->orderBy($sort, $dir);
产生了预期的 DQL:
ORDER BY INT(age) ASC
但也产生了异常:
在渲染模板期间抛出异常(“[Syntax Error] line 0, col 12272: Error: Expected end of string, got '('") in MyProject...
所以我试图找出发生了什么,并在Doctrine\ORM\Query\Parser.php 中了解了这一点:
/**
* OrderByItem ::= (
* SimpleArithmeticExpression | SingleValuedPathExpression |
* ScalarExpression | ResultVariable
* ) ["ASC" | "DESC"]
*
* @return \Doctrine\ORM\Query\AST\OrderByItem
*/
public function OrderByItem()
{
...
}
这是否意味着无法在ORDER BY 中使用 DQL 函数?
如果是这种情况 - 还有其他方法可以实现吗?
更新
我实际上已经在我的选择查询中使用了 INT,在 CASE WHEN 内:
if ($field->getFieldType() == 'number') {
$valueThen = "INT(".$valueThen.")";
}
$newFieldAlias = array("
(CASE
WHEN ...
THEN ".$valueThen."
ELSE ...
END
) as ".$field->getFieldKey());
稍后会将$newFieldAlias 添加到查询中。
不会改变任何东西...
更新 2
即使我在查询中添加了一个额外的选择,也会产生这个 DQL:
SELECT age, INT(age) as int_age
然后像这样排序:
ORDER BY int_age ASC
我仍然没有得到正确的结果。
我从$query->getResult() 中检查了var_dump,这就是我得到的:
'age' => string '57' (length=2)
'int_age' => string '57' (length=2)
喜欢 CAST 没关系。我一无所知...
【问题讨论】:
-
我想我解决这个问题的方法是给字段加上别名,然后按别名排序。因此,您可以在选择字段部分尝试 'INT(".$sort.") as SortBy',然后按该别名排序。
-
是的,对不起,我所有的教义都在起作用,所以我无法检查它,但我确实记得遇到过类似的问题。
标签: php mysql symfony doctrine-orm sql-order-by