You need to enable JavaScript to run this app. 如何搭配@PrimaryKeyJoinColumn使用QueryDsl查询无关联子表记录
优惠活动
大模型
产品
解决方案
定价
更多

如何搭配@PrimaryKeyJoinColumn使用QueryDsl查询无关联子表记录

QueryDSL 筛选无关联子表记录解决方案

问题原因

直接通过QBooking.booking.editor.id访问关联属性时,QueryDSL默认会生成内连接(INNER JOIN),内连接会直接过滤掉没有匹配editor关联的booking记录,后续再加editor.id is null的条件自然不可能匹配到任何结果。
你预期的SQL使用CROSS JOIN会生成笛卡尔积,执行效率极低,并不推荐使用,以下两种方案生成的SQL逻辑更合理、性能更优。

前置修正

首先确认关联注解配置正确,可选关联需要显式指定optional属性:

class Booking {
    @Id
    long id;
    
    String status;
    
    // 显式指定关联为可选
    @OneToOne(optional = true)
    @PrimaryKeyJoinColumn
    public Editor editor;
}

实现方案

方案1:左连接 + 空值判断

手动指定左连接逻辑,保留无关联的booking记录后再做空值筛选。

注:该方案需要先注入JPAQueryFactory,Spring Boot默认会自动配置该Bean,直接@Autowired注入即可。

QBooking booking = QBooking.booking;
QEditor editor = QEditor.editor;

List<Booking> result = new JPAQueryFactory(entityManager)
        .selectFrom(booking)
        .leftJoin(booking.editor, editor)
        .where(
            booking.status.eq(2),
            editor.id.isNull()
        )
        .fetch();

方案2:NOT EXISTS 子查询(无需调整原有调用逻辑)

用子查询实现不存在关联判断,执行效率更高,完全兼容你现有QuerydslPredicateExecutor的调用方式,不需要调整DAO层代码:

QBooking booking = QBooking.booking;
QEditor editor = QEditor.editor;

BooleanBuilder booleanBuilder = new BooleanBuilder(predicate)
        .and(booking.status.eq(2))
        .and(JPAExpressions.selectFrom(editor)
                .where(editor.id.eq(booking.id))
                .notExists()
        );

dao.findAll(booleanBuilder.getValue());

生成的SQL逻辑如下:

select * from booking 
where booking.status = ?
and not exists (select 1 from editor where editor.id = booking.id)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.16 07:54:04