Я пытаюсь использовать функцию MySQL FIELD в предложении order by в запросе. Я предполагаю, что Doctrine 2 не поддерживает функцию FIELD из коробки - это правда? Если да, то как я могу его использовать? Должен ли я включить весь свой запрос в собственный запрос? Существует ли расширение Doctrine 2, которое добавляет эту функциональность?
Функция Doctrine 2 mysql FIELD в порядке
Ответ 1
Джереми Хикс, спасибо за ваше расширение. Я не знал, как связать вашу функцию с доктриной, но, наконец, я нахожу ответ.
$doctrineConfig = $this->em->getConfiguration();
$doctrineConfig->addCustomStringFunction('FIELD', 'DoctrineExtensions\Query\Mysql\Field');
Мне нужна функция FIELD
, чтобы упорядочить мои объекты, которые я выбираю выражением IN
. Но вы можете использовать эту функцию только в SELECT, WHERE, BETWEEN
, а не в ORDER BY
.
Решение:
$qb
->select("r, field(r.id, " . implode(", ", $ids) . ") as HIDDEN field")
->from("Entities\Round", "r")
->where($qb->expr()->in("r.id", $ids))
->orderBy("field");
Чтобы не добавлять псевдоним FIELD
в строку результатов, вам нужно поставить ключевое слово HIDDEN
. Таким образом, это, как быть способным значения порядка в выражении IN
в Доктрине 2.2.
Ответ 2
Вы можете добавить поддержку функции FIELD() DQL, но вместо этого реализовать ее как стандартное выражение SQL CASE.. WHEN. Таким образом, ваша функция будет работать как на MySQL, так и на Sqlite, что особенно полезно, если вы похожи на меня и хотите запускать свои модульные тесты в sqlite в памяти.
Этот класс во многом основан на работе Джереми Хикса (я просто изменил метод getSql())
class Field extends FunctionNode
{
private $field = null;
private $values = array();
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
// Do the field.
$this->field = $parser->ArithmeticPrimary();
// Add the strings to the values array. FIELD must
// be used with at least 1 string not including the field.
$lexer = $parser->getLexer();
while (count($this->values) < 1 ||
$lexer->lookahead['type'] != Lexer::T_CLOSE_PARENTHESIS) {
$parser->match(Lexer::T_COMMA);
$this->values[] = $parser->ArithmeticPrimary();
}
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
$query = '(CASE ' . $this->field->dispatch($sqlWalker);
for ($i=0, $limiti=count($this->values); $i < $limiti; $i++) {
$query .= ' WHEN ' . $this->values[$i]->dispatch($sqlWalker) . ' THEN ' . $i;
}
$query .= ' END)';
return $query;
}
}
Ответ 3
Вы можете написать собственное расширение DQL.
Ответ 4
Если поле, которое вы хотите "упорядочить по", является типом данных ENUM, тогда ORDER BY будет работать в том порядке, в котором значения были определены для этого поля ENUM.
Например, у меня была заявка, определенная как enum('n','pe','o','ap','c')
, которая давала странный порядок. Упорядочение было исправлено после обновления перечисления до: enum('ap','c','n','o','pe')