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

如何用Doctrine 2.5的createQuery()替代原生MySQL查询实现驼峰式结果?

迁移到Doctrine DQL实现驼峰式结果水合

完全理解你的需求——想要利用Doctrine自动将下划线列名转为驼峰式结果的特性,同时把原生MySQL查询迁移到DQL。下面我来详细拆解可行的方案,包括你计划的DQL迁移,以及其他替代选项:

一、为什么选择DQL(createQuery)是最优解?

Doctrine ORM默认使用UnderscoreNamingStrategy,它会自动完成数据库下划线列名和实体驼峰属性名的双向映射。当你用createQuery执行DQL时,查询结果会自动水合为实体对象(或驼峰键名的数组),完全符合你的需求。

简单DQL示例

假设你有一个User实体,数据库列是user_id、full_name,实体属性对应userId、fullName:

// 初始化EntityManager
$entityManager = ...;

// 编写DQL查询
$query = $entityManager->createQuery('SELECT u FROM App\Entity\User u WHERE u.userId = :id');
$query->setParameter('id', 123);

// 水合为实体对象(属性为驼峰)
$user = $query->getSingleResult();
echo $user->getFullName(); // 输出对应full_name列的值

// 或者水合为驼峰键名的数组
$userArray = $query->getSingleResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);
echo $userArray['fullName']; // 同样输出对应值

迁移原生查询到DQL的注意事项

  • 原生MySQL函数(比如DATE_FORMAT)需要替换为DQL支持的函数,或者自定义DQL函数扩展;
  • 关联查询直接使用DQL的关联语法(比如JOIN u.addresses a),无需手动写JOIN语句;
  • 复杂查询可以配合QueryBuilder(本质还是DQL),可读性和维护性更好:
$qb = $entityManager->createQueryBuilder()
    ->select('u', 'a')
    ->from(App\Entity\User::class, 'u')
    ->leftJoin('u.addresses', 'a')
    ->where('u.userId = :id')
    ->setParameter('id', 123);

$users = $qb->getQuery()->getResult();

二、其他替代方案(无需全量迁移DQL)

如果有部分原生查询暂时无法迁移到DQL,以下方案也能实现下划线到驼峰的结果转换:

1. 自定义结果集水合器

创建一个自定义水合器,专门处理原生查询结果的下划线转驼峰:

use Doctrine\ORM\Internal\Hydration\AbstractHydrator;

class CamelCaseArrayHydrator extends AbstractHydrator
{
    protected function hydrateAllData(): array
    {
        $result = [];
        while ($row = $this->_stmt->fetch(\PDO::FETCH_ASSOC)) {
            $camelCaseRow = [];
            foreach ($row as $key => $value) {
                // 下划线转驼峰逻辑
                $camelCaseKey = lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', $key))));
                $camelCaseRow[$camelCaseKey] = $value;
            }
            $result[] = $camelCaseRow;
        }
        return $result;
    }
}

注册并使用这个水合器:

// 注册自定义水合模式
$entityManager->getConfiguration()->addCustomHydrationMode(
    'CAMEL_CASE_ARRAY',
    CamelCaseArrayHydrator::class
);

// 执行原生查询并使用自定义水合
$rsm = new \Doctrine\ORM\Query\ResultSetMapping();
$rsm->addScalarResult('user_id', 'userId');
$rsm->addScalarResult('full_name', 'fullName');

$nativeQuery = $entityManager->createNativeQuery(
    'SELECT user_id, full_name FROM users WHERE user_id = ?',
    $rsm
);
$nativeQuery->setParameter(1, 123);

// 获取驼峰式结果数组
$user = $nativeQuery->getSingleResult('CAMEL_CASE_ARRAY');

2. 手动转换查询结果

写一个工具函数,在获取原生查询结果后手动转换下划线键为驼峰:

function underscoreToCamelCase(array $data): array
{
    $result = [];
    foreach ($data as $key => $value) {
        $camelCaseKey = lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', $key))));
        // 递归处理嵌套数组
        $result[$camelCaseKey] = is_array($value) ? underscoreToCamelCase($value) : $value;
    }
    return $result;
}

// 使用示例
$connection = $entityManager->getConnection();
$stmt = $connection->executeQuery('SELECT user_id, full_name FROM users WHERE user_id = ?', [123]);
$rawRow = $stmt->fetchAssociative();
$camelCaseRow = underscoreToCamelCase($rawRow);
// $camelCaseRow 结果为 ['userId' => 123, 'fullName' => 'xxx']

3. 确认实体映射的命名策略

如果你的实体映射配置正确,Doctrine会自动处理命名转换。检查实体的@Column注解,确保name属性对应数据库的下划线列名:

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class User
{
    #[ORM\Id]
    #[ORM\Column(name: 'user_id', type: 'integer')]
    private $userId;

    #[ORM\Column(name: 'full_name', type: 'string')]
    private $fullName;

    //  getter/setter...
}

只要映射正确,无论是DQL还是QueryBuilder的结果都会自动是驼峰式。

总结

  • 优先推荐迁移到DQL/QueryBuilder:这能充分利用Doctrine ORM的特性(比如实体生命周期、关联管理、查询缓存),同时原生支持驼峰式结果;
  • 特殊场景用替代方案:如果有复杂原生查询难以迁移,自定义水合器或手动转换是不错的补充。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 04:14:50