无法创建Doctrine ResultSetMapping以将原始SQL查询解析为单个数据库表

时间:2018-02-14 16:24:53

标签: php doctrine-orm doctrine concrete5

我正在尝试将原始SQL命令转换为Doctrine实体。 sql命令是:

        $sql = 'SELECT SUM(IF (SCORE = 1, 1, 0)) AS UPVOTE, SUM(IF (SCORE = -1, 1, 0)) AS DOWNVOTE, BLOCKID, ELEMENTID FROM Voting GROUP BY BLOCKID, ELEMENTID';

哪个有效,并从投票表中返回:

UPVOTE  DOWNVOTE  BLOCKID  ELEMENTID
1       1         3223     person1
3       2         3223     person2
0       1         3223     person3

我的控制器文件中有以下PHP代码,目前返回一个空数组:

    $sql = 'SELECT SUM(IF (SCORE = 1, 1, 0)) AS UPVOTE, SUM(IF (SCORE = -1, 1, 0)) AS DOWNVOTE, BLOCKID, ELEMENTID FROM Voting GROUP BY BLOCKID, ELEMENTID';
    $rsm = new ResultSetMapping();
    $rsm->addEntityResult('Concrete\Entity\Vote', 'u');
    $rsm->addFieldResult('u', 'blockid', 'blockid');
    $rsm->addFieldResult('u', 'elementId', 'elementId');
    $rsm->addFieldResult('u', 'score', 'score');
    $rsm->addFieldResult('u', 'id', 'id');
    $rsm->addFieldResult('u', 'ipAddress', 'ipAddress');
    $rsm->addFieldResult('u', 'created_at', 'created_at');

    $rsm->addScalarResult('upvote', 'upvote');
    $rsm->addScalarResult('downvote', 'downvote');

    $query = $this->em->createNativeQuery($sql, $rsm);    
    $results = $query->getResult();
    echo json_encode($results);

我已经尝试过查阅Doctrine文档,但我无法确定问题所在。我已经在我的表中的所有列上调用了addFieldResult(例如id,ipAddress,created_at),这些列在结果中根本不显示 - 这是否是必需的?

使用上面的代码我没有错误,只返回一个空数组。我错过了什么或者只是做错了吗?

1 个答案:

答案 0 :(得分:2)

您不需要使用本机查询来执行此类查询。您可以依靠CASE expressions来记录您的条件。使用查询构建器,您的查询将如下所示:

$results = $entityManager->createQueryBuilder()
        ->from('Concrete\Entity\Vote', 'v')
        ->select('v.elementId', 'v.blockId')
        ->addSelect('SUM(CASE WHEN v.score = 1 THEN 1 ELSE 0 END) AS upvote')
        ->addSelect('SUM(CASE WHEN v.score = -1 THEN 1 ELSE 0 END) AS downvote')
        ->groupBy('v.blockId')
        ->addGroupBy('v.elementId')
        ->getQuery()
        ->getResult();

如果您仍想使用原生查询,如果您只想从表中检索ResultSetMappingBLOCKID,则无需使用ELEMENTID执行此操作。只需使用addScalarResult,第一个参数是SELECT子句中出现的字段/别名的名称,第二个参数是您希望它在结果集中具有的别名。 (您可以添加第三个参数来指定要检索的标量值的类型,请参阅下面的block_idupvote)。

使用像这样的Vote实体:

/** @ORM\Table(name="votes") */
class Vote
{
    /**
     * @ORM\Column(name="id", type="integer", unique=true)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /** @ORM\Column(name="block_id", type="integer") */
    private $blockId;

    /** @ORM\Column(name="element_id", type="string") */
    private $elementId;

    /** @ORM\Column(name="score", type="integer") */
    private $score;
}

以下本机查询将输出与使用上述查询构建器构建的查询相同的结果。

$sql = 'SELECT SUM(IF (SCORE = 1, 1, 0)) AS upvote, SUM(IF (SCORE = -1, 1, 0)) AS downvote, block_id, element_id FROM votes GROUP BY block_id, element_id';
$rsm = new ResultSetMapping();
$rsm->addScalarResult('block_id', 'blockId', 'integer');
$rsm->addScalarResult('element_id', 'elementId');
$rsm->addScalarResult('upvote', 'upvote', 'integer');
$rsm->addScalarResult('downvote', 'downvote', 'integer');

$query = $em->createNativeQuery($sql, $rsm);    
$result = $query->getResult();

您将获得的唯一区别是upvote / downvote值将是整数而不是字符串,因为您可以在此处指定它(而您不能使用查询构建器)