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
相关产品推荐
相关产品推荐

