doctrine2中的自定义DQL函数 [英] Custom DQL functions in doctrine2
问题描述
如何在部分中使用自定义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或任何其他方式实现以下条件:
- 仅选择选择性字段
- 使用聚合函数按子表格实体分组
- 基于表关系的水合物数组,聚合函数结果
应该在子数组中。每次如果我们使用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.ymlconfig.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:
- Select only selective fields
- Group by child table entity using Aggregate Functions
- 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 adatetime
field, so you'll expect a fullDateTime
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 aDateTime
object cannot be created (it expectsY-m-d H:i:s
, and thedate
type expectsY-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屋!