对于一个项目,我需要以JSON格式提供大量不同的数据。所有信息都将在同一页面上使用,因此单个调用将导致最小的开销。所有信息都涉及相同的数据库对象,并且在页面上都是必需的。它基本上是一个特定类型中的一个或多个的对象数量的集合(这些类型都是布尔值),我们需要知道很多不同的变体。我使用下面的代码,但我的同事认为我把它放在JSON列表中的方式有点笨拙,代码可以有更好的性能。我怎么能改进这段代码?
public function getContactsStatisticsAction()
{
$response = new Response();
$json = array();
$em = $this->getDoctrine()->getEntityManager();
$cr = $em->getRepository('BlaCoreBundle:Company');
$json['numberOfCompanies'] = $cr->numberOfCompanies();
$json['numberOfAccounts'] = $cr->numberOfCompanies(array("typeAccount" => true));
$json['numberOfCompetitors'] = $cr->numberOfCompanies(array("typeCompetitor" => true));
$json['numberOfSuppliers'] = $cr->numberOfCompanies(array("typeSupplier" => true));
$json['numberOfOthers'] = $cr->numberOfCompanies(array("typeOther" => true));
$json['numberOfUnassigned'] = $cr->numberOfCompanies(array("typeAccount" => false, "typeCompetitor" => false,"typeSupplier" => false,"typeOther" => false));
$json['numberOfJustAccounts'] = $cr->numberOfCompanies(array("typeAccount" => true, "typeCompetitor" => false, "typeSupplier" => false));
$json['numberOfJustCompetitors'] = $cr->numberOfCompanies(array("typeAccount" => false, "typeCompetitor" => false, "typeSupplier" => false));
$json['numberOfJustSuppliers'] = $cr->numberOfCompanies(array("typeAccount" => false, "typeCompetitor" => false, "typeSupplier" => false));
$json['numberOfCompetitorAndAccounts'] = $cr->numberOfCompanies(array("typeAccount" => true, "typeCompetitor" => true, "typeSupplier" => false));
$json['numberOfCompetitorAndSuppliers'] = $cr->numberOfCompanies(array("typeAccount" => false, "typeCompetitor" => true, "typeSupplier" => true));
$json['numberOfSupplierAndAccounts'] = $cr->numberOfCompanies(array("typeAccount" => true, "typeCompetitor" => false, "typeSupplier" => true));
$json['numberOfCompaniesAndAccountsAndSuppliers'] = $cr->numberOfCompanies(array("typeAccount" => true, "typeCompetitor" => true, "typeSupplier" => true));
$response->setContent(json_encode($json));
return $response;
}
public function numberOfCompanies($filters = array())
{
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('count(c.id)');
$qb->from('BlaCoreBundle:Company', 'c');
$sizeFilters = count ($filters);
$keys = array_keys($filters);
if($sizeFilters >= 1){
$qb->where('c.' . $keys[0] . ' = ' . (int) $filters[$keys[0]]);
}
for($i = 1; $i < $sizeFilters; $i++){
$qb->andWhere('c.' . $keys[$i] . ' = ' . (int) $filters[$keys[$i]]);
}
return $qb->getQuery()->getSingleScalarResult();
}
答案 0 :(得分:3)
你的同事是对的。您应该在单个查询中获得所有标量结果。您将以这种方式最小化连接数。
对于非Doctrine案例,this answer解决了该主题。
这样的用户也提出了这个有趣的问题here,但都没有回答。
实际上我认为没有办法用 QueryBuilder 或 DQL 来解决这种查询。此外,在 Doctrine2.2 的官方文档中,JOIN
上没有SELECT
的示例。
您可以尝试的内容类似于以下DQL查询:
return $this->getEntityManager()->createQuery(
SELECT COUNT(c1) AS C1, COUNT(c2) AS C2, COUNT(c3) AS C3 FROM
BlaCoreBundle:Company c1, BlaCoreBundle:Company c2, BlaCoreBundle:Company c3
WHERE c1.prop1 = 'xxx' AND c2.prop2 > '100' AND c3.prop3 LIKE '%XYZ%')
->getResult();
当然WHERE子句是一般例子。
此查询将返回一个一个大小的数组,其中C1,C2和C3作为您计算的值的键。当然,使用JOIN变得很困难,无论你需要什么,但你总是可以使用WHERE IN (SELECT...)
和WHERE EXISTS (SELECT...)
,例如
SELECT COUNT(c1) AS C1, COUNT(c2) AS C2, COUNT(c3) AS C3 FROM
BlaCoreBundle:Company c1, BlaCoreBundle:Company c2, BlaCoreBundle:Company c3
WHERE c1.prop1 = 'xxx' AND c2.prop2 > '100' AND c3.prop3 LIKE '%XYZ%'
AND EXISTS (SELECT x FROM BlaCoreBundle:Entity x JOIN x.company comp WHERE x.prop = "valye" AND comp = c1)