Symfony Doctrine createQueryBuilder语法错误及createQuery未定义问题求解
报错原因说明
第一个DQL语法报错
createQueryBuilder() 方法仅接收查询别名作为入参,你直接传入完整SQL语句不符合Doctrine的调用规范,因此触发了DQL解析错误。同时你编写的查询本身存在多处语法错误:子查询中重复写WHERE关键字、OR前错误加逗号、参数名和绑定的参数不对应。
第二个createQuery不存在报错
createQuery 是EntityManager的方法,不属于Repository类的内置方法。你调用不存在的类方法时触发了Repository的__call魔术方法校验,该方法默认会把未定义的调用判定为魔法查询请求,因此返回了要求方法名以findBy/findOneBy开头的提示,和你当前自定义的方法名findByBookings无关。
修复方案
首先需要确认你当前的Repository类已正确继承Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository,示例如下:
use App\Entity\Room; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Persistence\ManagerRegistry; class RoomRepository extends ServiceEntityRepository { public function __construct(ManagerRegistry $registry) { parent::__construct($registry, Room::class); } // 自定义方法写在此处 }
方案1:用QueryBuilder构造DQL查询(推荐)
按照你的需求(查询指定时间段内未被预订的房间),简化后的查询逻辑如下:
public function findByBookings($start, $leave): array { return $this->createQueryBuilder('r') ->leftJoin('r.bookings', 'b') // 需提前在Room实体中定义和Booking实体的OneToMany关联 ->where('b.id IS NULL OR b.startDate >= :leave OR b.leaveDate <= :start') ->setParameter('start', $start) ->setParameter('leave', $leave) ->getQuery() ->getResult(); }
注:两个时间段重叠的判断逻辑可简化为 预订开始时间 < 离开时间 AND 预订离开时间 > 入住时间,上述查询取的是不重叠的情况。
方案2:执行原生SQL查询
如果不想定义实体关联,可以直接调用数据库连接执行原生SQL:
public function findByBookings($start, $leave): array { $conn = $this->getEntityManager()->getConnection(); $sql = 'SELECT r.* FROM room r WHERE r.id NOT IN ( SELECT b.room_id FROM booking b WHERE b.startDate <= :leave AND b.leaveDate >= :start )'; $stmt = $conn->prepare($sql); $res = $stmt->executeQuery([ 'start' => $start, 'leave' => $leave ]); return $res->fetchAllAssociative(); }
内容的提问来源于stack exchange,提问作者Jojo l'artichaut
相关产品推荐
相关产品推荐

