symfony2 关联查询核心是 doctrine querybuilder 的 join() 和 leftjoin() 方法,需基于实体映射关系而非手写 sql;join() 实现内连接,仅返回关联双方均有数据的记录;leftjoin() 保留主表全部记录,关联表无匹配则字段为 null;多对多 and 查询需多次 join 并用不同别名与参数;join 后的别名可用于 select、where、orderby 等操作。

Symfony2 中做关联查询,核心是 Doctrine QueryBuilder 的 join() 和 leftJoin() 方法,配合实体间已定义的映射关系。关键不在写 SQL,而在理解对象关系与生成的 SQL 逻辑是否一致。
基础 JOIN:内连接查有对应关系的数据
当两个实体存在关联(如 User 有多篇 Post),用 join() 表示“只取两边都有数据的记录”。比如查用户及其文章标题:
$qb = $this->createQueryBuilder('u');$qb->select('u.username', 'p.title')->join('u.posts', 'p');- 这里
'u.posts'是 User 实体中定义的关联属性名(不是数据库字段),'p'是给关联表起的别名 - 生成的 SQL 相当于
SELECT ... FROM user u INNER JOIN post p ON u.id = p.user_id
LEFT JOIN:保留主表所有记录,关联表无匹配则补 NULL
想列出所有用户,不管他们有没有发过文章,就该用 leftJoin():
$qb->select('u.username', 'p.title')->leftJoin('u.posts', 'p');- 结果中没发过文章的用户,
p.title会是null - 注意:若在
WHERE条件里对左联表字段加非空限制(如andWhere('p.status = :status')),实际效果会退化为内连接——因为null不满足条件
多对多 AND 查询:多次 JOIN + 独立别名
查“既是红色又是大号的产品”,不能只 join 一次属性表再写两个 and 条件。单行记录的属性 slug 不可能同时等于两个值。
- 必须为每个属性条件单独 join:
join('p.attributes', 'a0')和join('p.attributes', 'a1') - 每个 join 后立即加对应条件:
andWhere('a0.slug = :slug0')、andWhere('a1.slug = :slug1') - 别名(
a0/a1)和参数名(:slug0/:slug1)必须不同,否则数据库无法区分匹配路径
关联字段过滤与排序:在 JOIN 后直接操作别名
JOIN 出来的表别名可以像主表一样用于 select、where、orderBy:
-
$qb->addSelect('c.name')->join('p.channel', 'c')—— 把频道名称也查出来 -
$qb->where('c.status = :status')—— 按频道状态过滤 -
$qb->addOrderBy('p.createdAt', 'DESC')—— 按文章创建时间倒序 - 注意:
where()和andWhere()效果相同,后者更常用于动态拼接条件











