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

Symfony4.4+Doctrine2.8:存储过程结果映射实体并分组方案

可行解决方案(基于Symfony 4.4 + Doctrine ORM 2.8 + MariaDB 10.5)

方案1:原生连接处理多结果集(无实体/数据库字段修改)

直接使用Doctrine的原生PDO连接绕过ORM的结果集限制,手动遍历所有返回的结果集并映射为Product实体,同时按结果集顺序标记来源。

// 在Controller或Service中执行
$entityManager = $this->getDoctrine()->getManager();
$connection = $entityManager->getConnection();

try {
    // 调用存储过程
    $stmt = $connection->prepare('CALL your_stored_procedure()');
    $stmt->execute();

    // 处理第一组结果集(标记为来源A)
    $groupA = [];
    while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
        // 用Repository的自定义方法或手动实例化实体
        $product = $entityManager->getRepository(Product::class)->createEntity($row);
        $groupA[] = [
            'source' => 'group_a',
            'product' => $product
        ];
    }

    // 切换到下一个结果集
    $stmt->nextRowset();

    // 处理第二组结果集(标记为来源B)
    $groupB = [];
    while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
        $product = $entityManager->getRepository(Product::class)->createEntity($row);
        $groupB[] = [
            'source' => 'group_b',
            'product' => $product
        ];
    }

    // 若有更多结果集,重复nextRowset和遍历步骤
    $stmt->closeCursor();
} catch (\Exception $e) {
    // 异常处理逻辑
}

说明:

  • createEntity是ProductRepository中自定义的方法,负责将数据库返回的数组映射为Product实体;也可以手动实例化实体并逐个赋值
  • 完全不需要修改实体类或数据库表结构,通过结果集顺序区分数据来源

方案2:瞬态字段映射UNION结果(无数据库字段修改)

在Product实体中添加一个瞬态属性(不映射到数据库),用来存储存储过程返回的FLAG标记,通过ResultSetMapping手动完成字段映射。

第一步:修改Product实体

// src/Entity/Product.php
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity()
 */
class Product
{
    // 原有实体字段及映射...

    /**
     * 瞬态属性:仅用于标记数据来源,不映射到数据库
     * @var string|null
     */
    private $sourceFlag;

    // 对应getter/setter
    public function getSourceFlag(): ?string
    {
        return $this->sourceFlag;
    }

    public function setSourceFlag(string $sourceFlag): self
    {
        $this->sourceFlag = $sourceFlag;
        return $this;
    }
}

第二步:调用存储过程并映射结果

$entityManager = $this->getDoctrine()->getManager();

// 创建原生查询并构建结果集映射
$query = $entityManager->createNativeQuery(
    'CALL your_union_based_procedure()',
    new \Doctrine\ORM\Query\ResultSetMappingBuilder($entityManager)
);

$rsm = $query->getResultSetMapping();
// 映射Product实体的原有字段
$rsm->addEntityResult(Product::class, 'p');
$rsm->addFieldResult('p', 'id', 'id');
$rsm->addFieldResult('p', 'name', 'name');
// 映射存储过程返回的FLAG字段到瞬态属性
$rsm->addFieldResult('p', 'FLAG', 'sourceFlag');

// 获取结果并分组
$allProducts = $query->getResult();
$groupedProducts = [];
foreach ($allProducts as $product) {
    $flag = $product->getSourceFlag();
    if (!isset($groupedProducts[$flag])) {
        $groupedProducts[$flag] = [];
    }
    $groupedProducts[$flag][] = $product;
}

说明:

  • 瞬态属性不会生成数据库字段,仅在内存中存储来源标记
  • 适合需要保留ORM查询特性的场景,同时满足不修改数据库结构的要求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 18:50:06