it-swarm.com.de

Konvertierung von MySQL in Doctrine Query Builder. Probleme mit IF und CONCAT. Oder ein anderer Ansatz für Unterabfragen bei Auswahl

Ich habe eine Tabelle für meine Kategorien, jede Kategorie hat eine ID, einen Namen und eine Eltern-ID.

Select IF(a.parent_id IS NULL, a.name, CONCAT((SELECT b.name FROM category b WHERE b.id = a.parent_id), " / ", a.name) ) as n, a.id, a.parent_id
FROM category a
ORDER BY n

Ich möchte es in meinen Doctrine2 Query Builder konvertieren

    $em = $this->getDoctrine()->getEntityManager();
    $qb = $em->createQueryBuilder();
    $q = $qb
            ->select("c.id")
            ->addSelect(
                "IF(c.parent_id IS NULL, c.name, CONCAT((" .
                $em->createQueryBuilder()
                   ->select("t.name")
                   ->from("MyBundle:Category", "t")
                   ->getQuery()->getDQL() .
                "), \" / \", c.name) )"
            )
            ->from("MyBundle:Category", "c");
    echo $q->getQuery()->getSQL();
    exit;

So etwas ähnliches, aber ich kann nicht IF und CONCAT verwenden.

24
Thiago Festa

Ok, ich habe die Lösung gefunden.

Sie können CASE anstelle von IF verwenden. Überprüfen Sie dies, aber wenn ich CASE verwende, kann ich meine Felder nicht CONCAT:

$em = $this->getDoctrine()->getEntityManager();
$qb = $em->createQueryBuilder();
$q = $qb
      ->select("c.id")
      ->addSelect("CASE WHEN (c.parent IS NULL) THEN c.name ELSE 'something' END")
      ->from("MyBundle:Category", "c")
      ->leftJoin("c.parent", "t");

echo $q->getQuery()->getSQL();

Eine andere Lösung ist die Erstellung Ihrer eigenen DQL-Funktion wie IF und verwenden Sie diese wie folgt:

$em = $this->getDoctrine()->getEntityManager();
$qb = $em->createQueryBuilder();
$q = $qb
      ->select("c.id")
      ->addSelect("IF(c.parent IS NULL, c.name, CONCAT(CONCAT(t.name, ' / '), c.name))")
      ->from("MyBundle:Category", "c")
      ->leftJoin("c.parent", "t");

echo $q->getQuery()->getSQL();

Um diese IF zu erstellen, können Sie zu diesem Link gehen und erfahren: http://docs.doctrine-project.org/projects/doctrine-orm/de/latest/reference/dql-doctrine-query-language.html#adding -Ihre-eigene-Funktionen-zur-Dql-Sprache

Ich werde hier meine Klasse für dieses IF und die config.yml posten, um anderen Menschen zu helfen ... Hier ist die IfFunction-Klasse (ich habe das von https://github.com/beberlei/DoctrineExtensions/blob/master/ src/Query/Mysql/IfElse.php ):

<?php
namespace MyName\MiscBundle\Doctrine\ORM\Query\AST\Functions;

use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;

/**
 * Usage: IF(expr1, expr2, expr3)
 * 
 * If expr1 is TRUE (expr1 <> 0 and expr1 <> NULL) then IF() returns expr2;
 * otherwise it returns expr3. IF() returns a numeric or string value,
 * depending on the context in which it is used. 
 * 
 * @author  Andrew Mackrodt <[email protected]>
 * @version 2011.06.19
 */
class IfFunction extends FunctionNode
{
    private $expr = array();

    public function parse(\Doctrine\ORM\Query\Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);
        $this->expr[] = $parser->ConditionalExpression();

        for ($i = 0; $i < 2; $i++)
        {
            $parser->match(Lexer::T_COMMA);
            $this->expr[] = $parser->ArithmeticExpression();
        }

        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }

    public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
    {
        return sprintf('IF(%s, %s, %s)',
            $sqlWalker->walkConditionalExpression($this->expr[0]),
            $sqlWalker->walkArithmeticPrimary($this->expr[1]),
            $sqlWalker->walkArithmeticPrimary($this->expr[2]));
    }
}

Danach musst du deine config.yml so aktualisieren (nur die letzten 3 Zeilen hinzugefügt):

doctrine:
    dbal:
        driver:   "%database_driver%"
        Host:     "%database_Host%"
        port:     "%database_port%"
        dbname:   "%database_name%"
        user:     "%database_user%"
        password: "%database_password%"
        charset:  UTF8

    orm:
        auto_generate_proxy_classes: "%kernel.debug%"
        auto_mapping: true
        dql: #ADDED THIS LINE
            string_functions: #ADDED THIS LINE
                IF: MyName\MiscBundle\Doctrine\ORM\Query\AST\Functions\IfFunction #ADDED THIS LINE

Vielen Dank

54
Thiago Festa

Sie können auch CASE und CONCAT kombinieren:

$q = $this->createQueryBuilder('a')
    ->select('a.id')
    ->addSelect('CASE WHEN(a.parent IS NULL) THEN \'\' else CONCAT(:variable, a.name, \'string\') END as name')
    ->setParameter('variable', $variable)
    ... ;
2
justb3a

Angenommen, Sie haben eine Beziehung namens "Eltern" in Kategorie. Funktioniert dies besser? :

$em = $this->getDoctrine()->getEntityManager();
$qb = $em->createQueryBuilder();
$q  = $qb
      ->select("c.id")
   ->addSelect("IF (c.parent_id IS NULL, c.name, CONCAT(t.name, ' / ', c.name))"
        ->from("MyBundle:Category", "c")
    ->leftJoin("c.parent t"));

echo $q->getQuery()->getSQL();
0
greg0ire