我必须简单的实体:日志和用户。日志与实体具有ManyToOne关系。
Log:
type: entity
repositoryClass: LogRepository
id:
id:
type: integer
generator:
strategy: AUTO
fields:
message:
type: string
manyToOne:
user:
targetEntity: User
joinColumns:
user_id:
referencedColumnName: id
我的用例是显示日志列表和一两个关于用户的信息(比如他的名字和邮件)
如果我使用findall
方法,Symfony调试工具栏会显示Doctrine执行大量查询。一个查询给我日志,每个用户执行一个查询!这当然不好,因为我可以看到一千根原木。我不想让我的数据库服务器过载。这个问题似乎很容易解决。但我搜索了一段时间,结果似乎是"糟糕的做法"。
因此,我开始在LogRepository类中使用querybuilder:编写一个新方法
public function getLog(){
$qb = $this->createQueryBuilder('l')
->select('l')
->innerJoin(
'ApplicationSonataUserBundle:User', 'u',
Expr'Join::WITH,'l.user = u.id')
;
return $qb->getQuery()->getResult();
}
我仍然有同样的问题。我已将方法上的选择参数更改为:
public function getLog(){
$qb = $this->createQueryBuilder('l')
->select('l','u')
->innerJoin('ApplicationSonataUserBundle:User','u',
Expr'Join::WITH,'l.user = u.id')
;
return $qb->getQuery()->getResult();
}
尤里卡?好吧,我只有一个查询,但我的方法并没有只返回Log,而是返回User。。。所以我的Twig模板崩溃了,因为我的循环包含User,而不仅仅是Log。当这是一个用户时,我的视图会崩溃,因为我想写消息字段。(Log.message存在。但User.message当然不是有效字段)
如果我再改变一次我的方法,用一个循环来过滤我的结果,它的效果非常好:
public function getLog(){
$qb = $this->createQueryBuilder('l')
->select('l','u')
->innerJoin('ApplicationSonataUserBundle:User','u',
Expr'Join::WITH,'l.user = u.id')
;
//THE STRANGE LOOP
$results = array();
foreach ($qb->getQuery()->getResult() as $result){
if ($result instanceof Log){
$results[] = $result;
}
};
return $results;
}
我只有一个查询,那就是我正在搜索的内容。我的小树枝模板不会崩溃,因为我的数组只包含Log。
那怎么了?它是有效的,但我认为这不是好的/最佳的做法。
有人可以向我解释一种更好的方法,一种使用内部联接查询的更好实践,以最小化执行的查询,并获得只包含Log实例的ArrayCollection结果?
应该没有必要使用循环。尝试如下:
public function getLog(){
$qb = $this->createQueryBuilder('l')
->select('l','u')
->innerJoin('l.user', 'u');
$logs = $qb->getQuery()->getResult();
return $logs;
}
它应该只返回具有已填充(fetch joined)的关联用户的$logs
。