dql是doctrine orm的面向对象查询语言,操作实体类和属性,天然防sql注入;基础结构为select+from+where,需用完整命名空间和别名;单条结果用getsingleresult()并捕获noresultexception/nonuniqueresultexception;关联查询需显式join并addselect;动态条件应使用expr()避免字符串拼接。

DQL(Doctrine Query Language)是 Symfony 中 Doctrine ORM 提供的面向对象查询语言,它不操作数据库表和字段,而是操作实体类和属性,天然防 SQL 注入、类型安全、易于维护。
基础 DQL 查询写法
最简结构是 SELECT + FROM + WHERE,实体名用 Bundle:Entity 或完整命名空间,别名必须声明:
- SELECT p —— 选择整个 Product 实体对象(返回 Product 实例数组)
-
FROM App\Entity\Product p —— 指定主实体及别名
p(Symfony 6+ 推荐用完整类名;旧版可用AcmeStoreBundle:Product) -
WHERE p.price > :price —— 条件中用冒号前缀的参数占位符,实际值通过
setParameter()绑定
示例:
$query = $em->createQuery('SELECT p FROM App\Entity\Product p WHERE p.price > :price')
->setParameter('price', 19.99);
$products = $query->getResult();
获取单条结果与异常处理
DQL 查询默认返回集合。若确定只有一条结果(如按主键查),应使用 getSingleResult(),但必须包裹 try-catch,否则查不到或查到多条会抛异常:
- 查不到 → 抛
NoResultException - 查到多条 → 抛
NonUniqueResultException - 推荐加
->setMaxResults(1)显式限制,提升语义清晰度和安全性
示例:
try {
$product = $em->createQuery('SELECT p FROM App\Entity\Product p WHERE p.sku = :sku')
->setParameter('sku', 'ABC-123')
->setMaxResults(1)
->getSingleResult();
} catch (\Doctrine\ORM\NoResultException $e) {
$product = null;
}
关联查询(JOIN)与预加载
多对一、一对多、多对多关系需显式 JOIN 才能取到关联数据,否则懒加载可能触发 N+1 查询或模板中访问为空:
-
leftJoin('p.category', 'c') —— 左连接 Category 实体,别名为
c(字段名category需与 Product 实体中定义的关联属性名一致) -
addSelect('c') —— 必须添加,否则 Doctrine 不会初始化
$p->getCategory(),即使写了 JOIN - 用
innerJoin可限制只返回有关联的数据(如只查有分类的商品)
示例(查商品及其分类名称):
$qb = $em->createQueryBuilder();
$products = $qb->select('p', 'c.name as categoryName')
->from('App\Entity\Product', 'p')
->innerJoin('p.category', 'c')
->where('p.isActive = :active')
->setParameter('active', true)
->getQuery()
->getResult();
动态条件与安全拼接
避免字符串拼接条件。用 expr() 构造动态 WHERE 子句,尤其适合搜索、筛选等不确定条件的场景:
-
$qb->expr()->like('p.name', ':name')→ 生成p.name LIKE ? -
$qb->expr()->in('p.status', ':statuses')→ 支持数组参数:setParameter('statuses', ['draft', 'published']) - 多个条件统一用
andWhere()追加,比反复写where()更健壮
示例(带模糊搜索与状态过滤):
$qb = $em->createQueryBuilder();
$qb->select('p')->from('App\Entity\Product', 'p')
->where($qb->expr()->like('p.name', ':keyword'))
->andWhere('p.status IN :statuses')
->setParameter('keyword', '%' . $keyword . '%')
->setParameter('statuses', ['active', 'archived']);











