doctrine2中的自定义DQL函数 [英] Custom DQL functions in doctrine2

查看:142
本文介绍了doctrine2中的自定义DQL函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在部分中使用自定义DQL函数来水化查询结果。



寻找在createQuery或任何其他原则方法中使用DQL函数的方法(nativeSql,QueryBuilder)它不是必须使用部分,但它应该根据表的关系水合我的数组,它应该只选择选择性字段



以下查询工作正常:

  $ q = $ em-> createQuery(select
。partial t。 {id,description},
。partial ut。{id,firstName,lastName,email},
。DATE_FORMAT(ut.created,'%m-%d-Y')
。from PMIUserBundle:Task t LEFT JOIN t.users ut);

DATE_FORMAT(ut.created,'%m-%d-Y')工作正常的部分。



DATE_FORMAT 已在config.yml中注册为自定义功能



config.yml:

  dql:
datetime_functions:
DATE_FORMAT:PMI \UserBundle\DoctrineFunctions\DateFormat

以下查询创建问题:

  $ q = $ em-> createQuery(select
。partial t。{id,description},
。partial ut。{id,firstName,lastName,email,DATE_FORMAT(created,'%m-%d-Y')},
。DATE_FORMAT(ut.created,'%m-%d- Y')
。from PMIUserBundle:Task t LEFT JOIN t.users ut);

给出错误:

  [Syntax Error] line 0,col 91:Error:Expected Doctrine\ORM\Query\Lexer :: T_CLOSE_CURLY_BRACE,got'('
pre>

以下是我的DateFormat类:

  class DateFormat extends \\ \\Doctrine\ORM\Query\AST\Functions\FunctionNode {



protected $ dateExpression;

protected $ formatChar;

public function getSql(\Doctrine\ORM\Query\SqlWalker $ sqlWalker){

return'DATE_FORMAT('。
$ sqlWalker-> ; walkArithmeticExpression($ this-> dateExpression)
','。
$ sqlWalker-> walkStringPrimary($ this-> formatChar)
')';



}

public function parse(\Doctrine\ORM\Query\Parser $ parser){

$ parser-> match(Lexer :: T_IDENTIFIER);
$ parser-> match(Lexer :: T_OPEN_PARENTHESIS);

$ this-> dateExpression = $ parser-> ArithmeticExpression();
$ parser-> match(Lexer :: T_COMMA);


$ this-> formatChar = $ parser-> StringPrimary();
$ parser-> match(Lexer :: T_CLOSE_PARENTHESIS);


}

}

编辑:



好的,所以Partial不会允许我使用DQL函数。感谢 FuzzyTree ,解决方案使用 ut-> getFormattedCreatedDate()我的实体类。但是我仍然很好奇,如果我们使用mysql聚合函数分组子表和计算一些数量,该怎么办?



如何在doctrine2中使用createQuery,queryBuilder,nativeSQl或任何其他方式实现以下条件:


  1. 仅选择选择性字段

  2. 使用聚合函数按子表格实体分组

  3. 基于表关系的水合物数组,聚合函数结果
    应该在子数组中。每次如果我们使用DQL函数,我们是否必须为这个类创建类为DateFormat创建?如果我们使用嵌套的MySql函数,如

      GROUP_CONCAT(DISTINCT CONCAT(tags.id,',',tags.displayName) 

    感谢您阅读我的问题。

    解决方案

    不支持



      PARTIAL ut。{id,firstName,lastName,email,DATE_FORMAT (创建,'%m-%d-Y')} 

    在选择这样的部分实体是不支持



    它也没有什么意义,在这种情况下,你可能(可能) 创建作为 datetime 字段,因此您将期望一个完整的 DateTime value,但现在你突然只是使用日期部分,更糟糕的是,你已经格式化了这个值,这样一个 DateTime 对象无法创建(它期望 Ymd H:i:s ,而日期类型期望 YMD )。



    对于任何部分选择:您不能,不应更改字段的值。 p>

    替代



    代替水化成部分实体,您只需使用数组即可。使用 $ q-> getArrayResult() $ q-> getScalarResult(),无论哪个更适合您的目的。



    如果你喜欢,你可以将结果分组/嵌套在Repository方法中。示例:

      public function getSomeData()
    {
    $ result = array();

    $ dql =<<< EOQ
    SELECT
    t.id AS t_id,
    t.description AS t_description,
    u.id AS u_id,
    u.firstName AS u_firstName,
    u.lastName AS u_lastName,
    u.email AS u_email,
    DATE_FORMAT(u.created,'%m-%d- Y')AS u_created
    FROM PMIUserBundle:Task t
    LEFT JOIN t.users u
    EOQ;

    $ q = $ this-> getEntityManager() - > createQuery($ dql);

    foreach($ q-> getScalarResult()as $ row){
    if(!isset($ result [$ row ['t_id']])){
    $ result [$ row ['t_id']] = array(
    'id'=> $ row ['t_id'],
    'description'=> $ row ['t_description'],
    'users'=> array()
    );

    $ result [$ row ['t_id']] ['users'] [] = array(
    'u.id'=> $ row ['u_id'],
    'u.firstName'=> $ row ['u_firstName'],
    'u.lastName'=> $ row ['u_lastName'],
    'u.email'=> ; $ row ['u_email'],
    'u.created'=> $ row ['u_created']
    );
    }
    }

    return $ result;
    }



    嵌套DQL函数



    嵌套DQL函数应该没有问题(如果你正确写了它们)。而 DISTINCT 支持开箱即用。


    How do you use custom DQL functions in partials to hydrate query result.

    Looking for a way to use DQL functions in createQuery or any other doctrine way (nativeSql, QueryBuilder) its not necessary to use partials but it should hydrate my array based on the relationship of tables and it should select only selective fields

    Following query works fine:

    $q = $em->createQuery("select "
                    . "partial t.{id, description}, "
                    . "partial ut.{id, firstName, lastName, email}, "
                    . "DATE_FORMAT(ut.created, '%m-%d-Y') "
                    . "from PMIUserBundle:Task t LEFT JOIN t.users ut");
    

    DATE_FORMAT(ut.created, '%m-%d-Y') works fine when its out of partial.

    DATE_FORMAT is already registered as custom function in config.yml

    config.yml:

    dql:
                datetime_functions:
                    DATE_FORMAT: PMI\UserBundle\DoctrineFunctions\DateFormat
    

    Following query creates issue:

     $q = $em->createQuery("select "
                    . "partial t.{id, description}, "
                    . "partial ut.{id, firstName, lastName, email, DATE_FORMAT(created, '%m-%d-Y')}, "
                    . "DATE_FORMAT(ut.created, '%m-%d-Y') "
                    . "from PMIUserBundle:Task t LEFT JOIN t.users ut");
    

    gives error:

    [Syntax Error] line 0, col 91: Error: Expected Doctrine\ORM\Query\Lexer::T_CLOSE_CURLY_BRACE, got '(' 
    

    Following is my DateFormat class:

    class DateFormat extends \Doctrine\ORM\Query\AST\Functions\FunctionNode {
    
    
    
        protected $dateExpression;
    
        protected $formatChar;
    
        public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) {
    
             return 'DATE_FORMAT('.
                    $sqlWalker->walkArithmeticExpression($this->dateExpression) .
                    ','.
                    $sqlWalker->walkStringPrimary($this->formatChar).
                    ')';
    
    
    
        }
    
        public function parse(\Doctrine\ORM\Query\Parser $parser) {
    
            $parser->match(Lexer::T_IDENTIFIER);
            $parser->match(Lexer::T_OPEN_PARENTHESIS);
    
            $this->dateExpression = $parser->ArithmeticExpression();
            $parser->match(Lexer::T_COMMA);
    
    
            $this->formatChar = $parser->StringPrimary();
            $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    
    
        }
    
    }
    

    EDIT:

    Ok, so Partial will not allow me to use DQL functions. Thanks to FuzzyTree for the solution to use ut->getFormattedCreatedDate() inside my entity class. But i am still curious what if we are grouping child table and calculating some amount using mysql Aggregate functions.

    How to achieve following criteria in doctrine2 using createQuery, queryBuilder, nativeSQl or any other way:

    1. Select only selective fields
    2. Group by child table entity using Aggregate Functions
    3. Hydrate array based on table relations, Aggregate functions results should be in child array.

    every time if we use DQL functions, do we have to create classes for that like i created for DateFormat ? what if we are using nested MySql functions like

    GROUP_CONCAT(DISTINCT CONCAT(tags.id,',',tags.displayName)
    

    Thank you for reading my question.

    解决方案

    Not supported

    PARTIAL ut.{id, firstName, lastName, email, DATE_FORMAT(created, '%m-%d-Y')}
    

    Using DQL functions inside the selection of partial entities like this is not supported.

    It doesn't make much sense either. In this case you've (probably) mapped the field created as a datetime field, so you'll expect a full DateTime value in there. But now you're suddenly just using the date part. And it get worse: you've formatted the value in such a way a DateTime object cannot be created (it expects Y-m-d H:i:s, and the date type expects Y-m-d).

    For any partial selection: You cannot, and should not, change the value of a field.

    Alternative

    In stead of hydrating into partial entities, you could just use arrays. Use $q->getArrayResult() or $q->getScalarResult(), whichever suits your purpose better.

    If you like, you can group/nest the results in the Repository method. Example:

    public function getSomeData()
    {
        $result = array();
    
        $dql = <<<EOQ
    SELECT
    t.id AS t_id,
    t.description AS t_description,
    u.id AS u_id,
    u.firstName AS u_firstName,
    u.lastName AS u_lastName,
    u.email AS u_email,
    DATE_FORMAT(u.created, '%m-%d-Y') AS u_created
    FROM PMIUserBundle:Task t
    LEFT JOIN t.users u
    EOQ;
    
        $q = $this->getEntityManager()->createQuery($dql);
    
        foreach ($q->getScalarResult() as $row) {
            if (!isset($result[$row['t_id']])) {
                $result[$row['t_id']] = array(
                    'id'          => $row['t_id'],
                    'description' => $row['t_description'],
                    'users'       => array()
                );
    
                $result[$row['t_id']]['users'][] = array(
                    'u.id'        => $row['u_id'],
                    'u.firstName' => $row['u_firstName'],
                    'u.lastName'  => $row['u_lastName'],
                    'u.email'     => $row['u_email'],
                    'u.created'   => $row['u_created']
                );
            }
        }
    
        return $result;
    }
    

    Nesting DQL functions

    Nesting DQL functions should be no problem (if you wrote them correctly). And DISTINCT is supported out of the box.

    这篇关于doctrine2中的自定义DQL函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆