You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Doctrine DQL未返回预期结果但对应MySQL查询正常

我太懂这种踩坑的感觉了!把原生MySQL转DQL的时候,最容易栽在关联条件的位置上——尤其是这种内连加带筛选条件的左连组合,稍微写错就会导致结果为空。先帮你理清楚原SQL的核心逻辑,再给你对应的DQL写法:

首先先贴下你的原生SQL方便对照:

SELECT vp.id 
FROM vehicle_photo AS vp 
INNER JOIN vehicle AS v ON vp.vehicle_id = v.id AND vp.manualMaintenanceCheckedOn IS NULL AND vp.type_id = 1 
LEFT JOIN vehicle_maintenance_history AS vmh ON vmh.vehicle_id = v.id AND vmh.source != 'kip' AND vmh.source != 'haan' 
WHERE vmh.vehicle_id IS NULL

原SQL逻辑拆解

  1. 先通过内连接筛选出未手动检查过维护(manualMaintenanceCheckedOn为空)且类型ID为1的车辆照片,同时关联对应的车辆
  2. 左连接车辆的维修记录,但只匹配来源不是kip和haan的记录
  3. 最后只保留那些完全没有符合上述条件的维修记录的车辆照片ID

对应的JPQL写法(适合直接用EntityManager)

String jpql = """
    SELECT vp.id 
    FROM VehiclePhoto vp 
    JOIN vp.vehicle v 
    LEFT JOIN v.vehicleMaintenanceHistories vmh 
        ON vmh.source != 'kip' AND vmh.source != 'haan' 
    WHERE vp.manualMaintenanceCheckedOn IS NULL 
      AND vp.type.id = 1 
      AND vmh IS NULL
""";

对应的Criteria Query写法(适合动态查询场景)

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> query = cb.createQuery(Long.class);

// 根实体是VehiclePhoto
Root<VehiclePhoto> vpRoot = query.from(VehiclePhoto.class);
// 内连Vehicle
Join<VehiclePhoto, Vehicle> vehicleJoin = vpRoot.join("vehicle", JoinType.INNER);
// 左连VehicleMaintenanceHistory,同时指定ON条件
Join<Vehicle, VehicleMaintenanceHistory> historyJoin = vehicleJoin.join(
    "vehicleMaintenanceHistories", 
    JoinType.LEFT
);
historyJoin.on(cb.and(
    cb.notEqual(historyJoin.get("source"), "kip"),
    cb.notEqual(historyJoin.get("source"), "haan")
));

// 组装查询条件和结果
query.select(vpRoot.get("id"))
     .where(
         cb.isNull(vpRoot.get("manualMaintenanceCheckedOn")),
         cb.equal(vpRoot.get("type").get("id"), 1),
         cb.isNull(historyJoin)
     );

List<Long> photoIds = entityManager.createQuery(query).getResultList();

关键注意点(也是你可能踩的坑)

  • 绝对不要把左连的source筛选条件放到WHERE里!如果这么做,会把左连接自动转换成内连接——因为WHERE会过滤掉所有vmh为null的记录,直接导致你拿不到结果
  • 确保你的实体类关联关系是正确的:VehiclePhoto里有vehicle属性,Vehicle里有vehicleMaintenanceHistories集合,属性名要和JPQL/Criteria里用的完全一致
  • 原SQL内连里的vp.manualMaintenanceCheckedOn IS NULL和vp.type_id=1,在DQL里放到WHERE子句更符合JPA规范,也更容易维护

内容的提问来源于stack exchange,提问作者angelus12

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:28:37