doctrine querybuilder是symfony中安全操作数据库的核心工具,支持面向对象查询、自动参数绑定防注入、实体关系映射;基础用法在repository中链式构建,动态条件按需添加,关联查询用leftjoin+addselect避免n+1,复杂逻辑通过expr()构建嵌套表达式。

Doctrine 查询构建器(QueryBuilder)在 Symfony 项目中是操作数据库最常用、最安全的方式之一,它用面向对象语法替代手拼 SQL,自动处理参数绑定、防止注入,并天然兼容 Doctrine ORM 的实体映射关系。
基础用法:从 Repository 开始
推荐把查询逻辑写在 Entity 对应的 Repository 类里(如 UserRepository),这样职责清晰、便于复用和测试。
- 在 Repository 中通过
$this->createQueryBuilder('u')获取构建器实例,'u'是别名,代表当前实体 - 链式调用
select()、from()、where()、andWhere()等方法组装查询 - 所有变量值必须用
setParameter()绑定,不能直接拼进字符串
示例:
public function findActiveUsers(): array
{
return $this->createQueryBuilder('u')
->where('u.status = :status')
->setParameter('status', 'active')
->orderBy('u.createdAt', 'DESC')
->getQuery()
->getResult();
}
动态条件:按需添加 where 子句
前端传来的筛选参数(如 status、minPrice、searchTerm)往往不固定,这时不能硬写死所有条件,而要判断后追加。
- 用
if检查参数是否存在,再调用andWhere()添加条件 - 每个条件都配一个独立的参数名(如
:minPrice),避免重复绑定冲突 - 注意:第一个条件用
where(),后续统一用andWhere()或orWhere()
示例:
public function findByFilters(array $filters): array
{
$qb = $this->createQueryBuilder('p');
if (isset($filters['category'])) {
$qb->andWhere('p.category = :category')
->setParameter('category', $filters['category']);
}
if (isset($filters['q']) && trim($filters['q'])) {
$qb->andWhere($qb->expr()->like('p.name', ':search'))
->setParameter('search', '%' . $filters['q'] . '%');
}
return $qb->getQuery()->getResult();
}
关联查询:一次查出主实体 + 关联数据
比如查订单时要同时带出用户信息,避免 N+1 查询问题,要用 leftJoin() 或 innerJoin() 配合 addSelect()。
-
leftJoin('p.user', 'u')表示左连接 User 实体,别名为u - 加上
addSelect('u')才会在结果中包含 User 对象(否则只返回 Order) - 关联字段筛选也支持,例如
->andWhere('u.isActive = true')
示例:
public function findOrdersWithUser(): array
{
return $this->createQueryBuilder('o')
->select('o', 'u')
->leftJoin('o.user', 'u')
->where('o.status != :status')
->setParameter('status', 'cancelled')
->getQuery()
->getResult();
}
复杂逻辑:用 expr() 构建 and/or 嵌套条件
当需要组合多个 AND/OR 条件(比如“状态是 active 且价格 >100,或者类型是 premium”),单靠链式 andWhere() 不够灵活,得用表达式生成器。
- 调用
$qb->expr()->andX()或orX()创建复合表达式 - 内部用
eq()、gt()、like()等方法构造原子条件 - 整个表达式作为
where()的参数传入
示例:
public function findSpecialProducts(): array
{
$expr = $this->getEntityManager()->getExpressionBuilder();
return $this->createQueryBuilder('p')
->where($expr->orX(
$expr->andX(
$expr->eq('p.status', ':active'),
$expr->gt('p.price', ':minPrice')
),
$expr->eq('p.type', ':premium')
))
->setParameter('active', 'active')
->setParameter('minPrice', 100)
->setParameter('premium', 'premium')
->getQuery()
->getResult();
}











