You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Doctrine原生SQL与ResultSet映射查询结果到ContactDTO?

可行,具体实现方案如下

完全可以通过Doctrine原生SQL结合ResultSetMapping将UNION查询结果直接映射到ContactDTO,以下是具体实现步骤:

1. 配置ResultSetMapping映射规则

根据你的ContactDTO结构,有两种常见映射方式,可按需选择:

方式一:用ConstructorResult自动映射(推荐)

如果你的ContactDTO定义了接收所有属性的构造函数,Doctrine可以自动实例化DTO并赋值:

// ContactDTO.php
class ContactDTO
{
    public function __construct(
        public int $id,
        public string $type,
        public string $firstname,
        public string $lastname,
        public string $email
    ) {}
}

查询时配置映射规则并执行:

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query\ResultSetMappingBuilder;

public function getCombinedContacts(EntityManagerInterface $em): array
{
    $rsm = new ResultSetMappingBuilder($em);
    // 绑定DTO类与查询字段的映射关系
    $rsm->addConstructorResult(
        ContactDTO::class,
        [
            $rsm->addFieldResult('dto', 'id', 'id'),
            $rsm->addFieldResult('dto', 'type', 'type'),
            $rsm->addFieldResult('dto', 'firstname', 'firstname'),
            $rsm->addFieldResult('dto', 'lastname', 'lastname'),
            $rsm->addFieldResult('dto', 'email', 'email'),
        ]
    );

    // 替换为你实际带条件的UNION查询
    $sql = <<<SQL
SELECT id, 'contact1' AS type, firstname, lastname, email FROM contact1 WHERE status = :active
UNION
SELECT id, 'contact2' AS type, firstname, lastname, email FROM contact2 WHERE status = :active
SQL;

    $query = $em->createNativeQuery($sql, $rsm);
    // 绑定参数,避免SQL注入
    $query->setParameter('active', 1);

    // 直接返回ContactDTO实例数组
    return $query->getResult();
}

方式二:标量结果手动转换

如果DTO没有构造函数,也可以先获取标量数组结果,再手动映射:

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query\ResultSetMapping;

public function getCombinedContacts(EntityManagerInterface $em): array
{
    $rsm = new ResultSetMapping();
    // 定义查询返回的标量字段别名
    $rsm->addScalarResult('id', 'id');
    $rsm->addScalarResult('type', 'type');
    $rsm->addScalarResult('firstname', 'firstname');
    $rsm->addScalarResult('lastname', 'lastname');
    $rsm->addScalarResult('email', 'email');

    $sql = <<<SQL
SELECT id, 'contact1' AS type, firstname, lastname, email FROM contact1 WHERE ...
UNION
SELECT id, 'contact2' AS type, firstname, lastname, email FROM contact2 WHERE ...
SQL;

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

    // 手动转换为DTO数组
    return array_map(function(array $row) {
        $dto = new ContactDTO();
        $dto->id = $row['id'];
        $dto->type = $row['type'];
        $dto->firstname = $row['firstname'];
        $dto->lastname = $row['lastname'];
        $dto->email = $row['email'];
        return $dto;
    }, $scalarResults);
}

2. 关键注意事项

  • 确保原生SQL返回的字段别名与DTO的属性名完全匹配,若别名不同,可通过addFieldResult指定映射,比如$rsm->addFieldResult('dto', 'contact_id', 'id')
  • 使用ConstructorResult时,DTO的构造函数参数顺序要与映射的字段顺序一致
  • 复杂子查询、分组、WHERE条件不影响映射,只要最终返回的字段符合映射规则即可
  • 所有外部参数必须用setParameter绑定,避免SQL注入

内容的提问来源于stack exchange,提问作者LinChan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 07:10:11