Symfony 3.4中Doctrine如何实现带子查询的JOIN关联查询
问题根因
报错是因为Doctrine使用的DQL查询语言是面向实体对象的,不识别原生SQL里的裸表名。你在子查询中直接写from activities a2,Doctrine会把activities解析为实体类名,找不到对应映射实体就会抛出语义错误。
另外你直接硬编码的sysdate()是数据库特定函数,Doctrine默认没有内置支持,即使解决了实体映射问题也可能触发函数不存在的报错。
可落地实现方案
因为你需要保留QueryBuilder链式调用、后续追加筛选条件的能力,无需把整段查询改成原生SQL,直接按下面的方式调整关联逻辑即可,完全兼容Symfony 3.4版本的Doctrine ORM:
- 单独构建子查询的QueryBuilder,不要把子查询硬拼接在WITH条件字符串里
- 子查询的from部分使用Doctrine映射的实体名,不要写数据库表名
- 用Doctrine内置日期函数替代数据库原生的sysdate()
示例代码如下:
// $em 是通过$this->getDoctrine()->getManager()获取的实体管理器 // 先构建取最大日期的子查询 $subQb = $em->createQueryBuilder(); $subQb->select('MAX(a2.date)') // 这里替换成你自己的Activity实体路径,Symfony3.4下支持Bundle名:实体名的简写形式 ->from('AppBundle:Activity', 'a2') ->where('a2.user = att.user') ->andWhere('a2.date <= CURRENT_DATE()'); // 主查询关联部分调整为 $query->leftJoin('p.activities', 'att', 'WITH', sprintf('att.date = (%s)', $subQb->getDQL()));
后续你要追加其他关联、列表筛选条件,直接在主$query对象上链式调用leftJoin、andWhere等方法即可,此时att别名只会关联到对应用户满足日期条件的最新一条activity记录,不会返回冗余的历史关联数据。
避坑提示
- DQL中所有引用的表、字段都要对应实体和实体属性,不能直接写数据库表名、列名:比如关联属性不要写
a2.user_id,要写你在Activity实体中定义的user关联属性名a2.user - 如果你的项目中Activity实体不在AppBundle下,把
AppBundle:Activity替换成你实际的实体Bundle名+实体名即可,比如属于AcmeDemoBundle就写AcmeDemoBundle:Activity - 你提供的原生SQL示例里存在笔误,
activites.user_id拼写少了字母i,写代码时注意核对别名不要写错
内容的提问来源于stack exchange,提问作者Mdk
相关产品推荐
相关产品推荐

