symfony2: cum se utilizează grup_concat în QueryBuilder

Am un set imbricat (folosind arborele Gedmo) numit "Locație". Entitatea "Appartment" are location_id și ce trebuie să fac pentru a mapa valoarea scalară numită de exemplu "calea" la interogarea care returnează toate apartamentele.

În Doctrină1, am avut acest cod:

/**
* Add "path" to each element
* 
* @param Doctrine_Query $query
* @param string $separator
*/
protected function addScalar_path(Doctrine_Query $query, $separator=", ")
{
    $subquery = "k99.root_id=o.root_id AND k99.lft<=o.lft AND k99.rgt>=o.rgt AND k99.level<=o.level" ;

    $query->addSelect("(SELECT GROUP_CONCAT(k99.name ORDER BY k99.level SEPARATOR '$separator') FROM Location k99 WHERE $subquery) AS path") ;
}

Notă: aliasul "o" este utilizat pentru interogarea primară. Acest cod mi-ar permite să folosesc

{foreach .... as $appartment}
   {$appartment->path}
...

Ceea ce va tipări:

Australia, Victoria, Melbourne, ...other children...

Cum sa faci acelasi lucru in D2? Și cum să includ și extensii de doctrine în proiectul meu symfony2?

18
adăugat autor j0k, sursa

4 răspunsuri

Dacă doriți să îl utilizați în QueryBuilder trebuie să:

1) add DQL functions GroupConcat: GroupConcat

2 ) Registering GroupConcat :DQL User Defined Functions

another alternative is to use NativeQuery :Native SQL


În simfony2 înregistrarea unei funcții DQL este foarte simplu doar să adăugați GROUP_CONCAT în config.yml cum ar fi:

    entity_managers:
        default:
            dql:
                string_functions:
                    GROUP_CONCAT: YourBundle\Query\Mysql\GroupConcat

For more information visit Registering Custom DQL Functions

28
adăugat
Soluția de adăugare a GroupConcat și de înregistrare a funcționat ca un farmec. Dacă utilizați ORM (lucruri implicite), config.yml merge după cum urmează: doctrine> orm> dql> string_functions> GROUP_CONCAT
adăugat autor jsgoupil, sursa
@ a.aitboudad Aveți idee cum să utilizați funcțiile DQL în doctrine2 partials?
adăugat autor hardik, sursa
Sunt foarte experimentat User Doctrine1 dar D2 ma ucide. Există un exemplu de cod pentru ceea ce am nevoie? De asemenea, am nevoie de QB în loc de NativeQuery. Și cum pot înregistra evenimentul GroupConcat în proiectul Symfony2?
adăugat autor Zeljko, sursa
+1 pentru SQL nativ. În afară de asta este un pic cam greu pentru doctrinarii neexperimentați care este încă cea mai bună soluție ...
adăugat autor Jovan Perovic, sursa
Vezi mai sus am adăugat modul de înregistrare a Group_Concat în Symfony2, dar pentru Native Query puteți vedea exemplul oficial,
adăugat autor a.aitboudad, sursa
@ yan-f link-uri actualizate mulțumesc!
adăugat autor a.aitboudad, sursa
Linia "nativă SQL" nu mai funcționează (permisiune respinsă)
adăugat autor Arkemlar, sursa
Am încercat ceea ce ați spus despre modul NativeSql, am folosit deja această metodă înainte, dar acum aceeași interogare care funcționează direct în phpmyadmin, returnează o matrice goală din interogarea doctrinară Nativă SQL ... SELECT GROUP_CONCAT (id) FROM PRODUCTS GROUP BY categorie, linie, tip
adăugat autor linuxatico, sursa

Dacă apare vreun mesaj, există acum un depozit Extensii doctrine în Github. Repo-ul are instrucțiuni despre cum să-l folosească. Puteți utiliza compozitorul pentru a-l instala și apoi utiliza orice funcție care vă interesează.

EDIT:

De dragul utilizatorului Tushar, modul de utilizare a GROUP_CONCAT în DQL a Doctrine2 este simplu de instalat Extensii de doctrină :

composer require beberlei/DoctrineExtensions

Pentru ao activa: adăugați următoarele în config.yml:

doctrine:
 orm:
     dql:
         string_functions:
             group_concat: DoctrineExtensions\Query\Mysql\GroupConcat

Apoi, în codul dvs., ar trebui să puteți acum să utilizați grupul Concat în DQL-urile dvs.:

$this->createQueryBuilder('location')
            ->select('location')
            ->addSelect("GROUP_CONCAT(DISTINCT location.name SEPARATOR '; ') AS locationNames");

        $result = $queryBuilder->getQuery()->getResult();

Sau în cazul întrebării inițiale:

$query->addSelect("(SELECT GROUP_CONCAT(k99.name ORDER BY k99.level SEPARATOR '$separator') FROM Location k99 WHERE $subquery) AS path");
12
adăugat

Doar o completare la răspunsul lui @ a.aitboudad:
Funcția DQL GroupConcat legată pare să aibă un "sprijin limitat pentru GROUP_CONCAT".
Iată versiunea completă de asistență: Configurația este așa cum a menționat el.

// -------------------------------------------------
// Complete support of GROUP_CONCAT in Doctrine2
// -------------------------------------------------
// Original Article: http://habrahabr.ru/post/181666/
// Automated translation to English: http://sysmagazine.com/posts/181666/ 
// Original github commit: https://github.com/denisvmedia/DoctrineExtensions/blob/d1caf21cd7c71cc557e60c26e9bf25323a194dd1/lib/DoctrineExtensions/Query/Mysql/GroupConcat.php

/**
 * DoctrineExtensions Mysql Function Pack
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to [email protected] so I can send you a copy immediately.
 */

namespace DoctrineExtensions\Query\Mysql;

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

/**
 * Full support for:
 *
 * GROUP_CONCAT([DISTINCT] expr [,expr ...]
 *              [ORDER BY {unsigned_integer | col_name | expr}
 *                  [ASC | DESC] [,col_name ...]]
 *              [SEPARATOR str_val])
 *
 */
class GroupConcat extends FunctionNode
{
    public $isDistinct = false;
    public $pathExp = null;
    public $separator = null;
    public $orderBy = null;

    public function parse(\Doctrine\ORM\Query\Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);

        $lexer = $parser->getLexer();
        if ($lexer->isNextToken(Lexer::T_DISTINCT)) {
            $parser->match(Lexer::T_DISTINCT);

            $this->isDistinct = true;
        }

       //first Path Expression is mandatory
        $this->pathExp = array();
        $this->pathExp[] = $parser->SingleValuedPathExpression();

        while ($lexer->isNextToken(Lexer::T_COMMA)) {
            $parser->match(Lexer::T_COMMA);
            $this->pathExp[] = $parser->StringPrimary();
        }

        if ($lexer->isNextToken(Lexer::T_ORDER)) {
            $this->orderBy = $parser->OrderByClause();
        }

        if ($lexer->isNextToken(Lexer::T_IDENTIFIER)) {
            if (strtolower($lexer->lookahead['value']) !== 'separator') {
                $parser->syntaxError('separator');
            }
            $parser->match(Lexer::T_IDENTIFIER);

            $this->separator = $parser->StringPrimary();
        }

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

    public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
    {
        $result = 'GROUP_CONCAT(' . ($this->isDistinct ? 'DISTINCT ' : '');

        $fields = array();
        foreach ($this->pathExp as $pathExp) {
            $fields[] = $pathExp->dispatch($sqlWalker);
        }

        $result .= sprintf('%s', implode(', ', $fields));

        if ($this->orderBy) {
            $result .= ' ' . $sqlWalker->walkOrderByClause($this->orderBy);
        }

        if ($this->separator) {
            $result .= ' SEPARATOR ' . $sqlWalker->walkStringPrimary($this->separator);
        }

        $result .= ')';

        return $result;
    }

}

// -------------------------------------------------
// Example of usage:
// -------------------------------------------------
$query = $this->createQueryBuilder('c')
    ->select("
            c as company,
            GroupConcat(b.id, ';', b.headOffice, ';', b.city, ';', s.name
            ORDER by b.id
            SEPARATOR '|') AS branches
        ")->leftJoin('c.branches', 'b')
    ->leftJoin('b.country', 's')
    ->groupBy('c.id')
    ->setFirstResult(0)
    ->setMaxResults(10)
    ->getQuery();
$result = $query->getResult();
7
adăugat
acesta este cel mai oribil mod de a folosi funcțiile MySQL în interogare. de ce doctrina2 sa limitat să folosească direct funcțiile mysql.
adăugat autor hardik, sursa
Au furat această funcție pe care mi-am scris-o, vă rog să schimbați creditul la acesta: habrahabr.ru/post/181666 (sysmagazine.com pare să fi făcut traducerea automată a articolului meu).
adăugat autor Denis V, sursa

Am avut o problemă similară. GROUP_CONCAT nu permite utilizarea CASE-WHEN înăuntru. Această bibliotecă mi-a rezolvat problemele, deci poate că va fi de ajutor.

0
adăugat