是否可以将SQL函数的结果用作Doctrine中的字段?

Mul*_*tis 12 php mysql sql symfony doctrine-orm

假设我有附加到产品的Product实体和Review实体.是否可以Product根据SQL查询返回的结果将字段附加到实体?喜欢附加ReviewsCount等于的字段COUNT(Reviews.ID) as ReviewsCount.

我知道可以在像这样的函数中做到这一点

public function getReviewsCount() {
    return count($this->Reviews);
}
Run Code Online (Sandbox Code Playgroud)

但我想用SQL来做这件事来最小化数据库查询的数量并提高性能,因为通常我可能不需要加载数百个评论,但仍然需要知道那里的数字.我认为运行SQL COUNT会比通过100个产品并为每个产品计算100个评论要快得多.而且,这只是一个例子,在实践中我需要更复杂的功能,我认为MySQL会更快地处理.如我错了请纠正我.

Jas*_*man 6

您可以将单列结果映射到实体字段 -查看本机查询ResultSetMapping以实现此目的。作为一个简单的例子:

use Doctrine\ORM\Query\ResultSetMapping;

$sql = '
    SELECT p.*, COUNT(r.id)
    FROM products p
    LEFT JOIN reviews r ON p.id = r.product_id
';

$rsm = new ResultSetMapping;
$rsm->addEntityResult('AppBundle\Entity\Product', 'p');
$rsm->addFieldResult('p', 'COUNT(id)', 'reviewsCount');

$query   = $this->getEntityManager()->createNativeQuery($sql, $rsm);
$results = $query->getResult();
Run Code Online (Sandbox Code Playgroud)

然后,在您的产品实体中,您将有一个$reviewsCount字段,计数将被映射到该字段。请注意,这仅在您在Doctrine元数据中定义了列的情况下才有效,例如:

/**
 * @ORM\Column(type="integer")
 */
private $reviewsCount;

public function getReviewsCount()
{
    return $this->reviewsCount;
}
Run Code Online (Sandbox Code Playgroud)

这是“ 汇总字段原则”文档中建议的内容。问题在于,您实际上是在使Doctrine认为数据库中还有一个名为的列reviews_count,这是您不想要的。因此,无需物理添加该列仍然可以使用,但是如果您运行过a,doctrine:schema:update它将为您添加该列。不幸的是,Doctrine并没有真正允许使用虚拟属性,因此另一种解决方案是编写您自己的自定义水化器,或者订阅该loadClassMetadata事件并在特定实体(一个或多个)加载后自己手动添加映射。

请注意,如果您执行类似的操作,COUNT(r.id) AS reviewsCount则您将无法再COUNT(id)addFieldResult()函数中使用它,而必须reviewsCount对第二个参数使用别名。

您也可以将其ResultSetMappingBuilder作为使用结果集映射的开始。

我的实际建议是手动执行此操作,而不要遍历所有这些额外的内容。本质上创建一个普通查询,该查询将实体和标量结果都返回到数组中,然后将标量结果设置为实体上对应的未映射字段,然后返回实体。


Tom*_*ski 1

是的,有可能,您需要使用QueryBuilder以下方法来实现:

$result = $em->getRepository('AppBundle:Product')
    ->createQueryBuilder('p')
    ->select('p, count(r.id) as countResult')
    ->leftJoin('p.Review', 'r')
    ->groupBy('r.id')
    ->getQuery()
    ->getArrayResult();
Run Code Online (Sandbox Code Playgroud)

现在你可以做类似的事情:

foreach ($result as $row) {
    echo $row['countResult'];
    echo $row['anyOtherProductField'];
}
Run Code Online (Sandbox Code Playgroud)

  • 问题是在这种情况下我得到一个与实体分离的标量。如果所有这些标量都附加到同一实体,这可能不是问题,但如果它们应该附加到不同的实体怎么办?就像我想选择产品和评论,对于产品我想要有评论的数量,而对于评论我想要有喜欢和不喜欢的数量。 (3认同)