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

Spring JPA查询NULL判断异常:含NULL的行被意外过滤

问题:Spring JPA查询意外过滤institution为NULL的Post记录

编写JPQL查询@Query("SELECT p FROM PostDAO p WHERE true OR p.user.institution IS NOT NULL"),预期等同于@Query("SELECT p FROM PostDAO p WHERE true")返回所有Post记录,但实际所有institution为NULL的Post行被过滤。

还尝试过以下查询,结果依然排除了institution为NULL的Post:

  • SELECT p FROM PostDAO p WHERE true OR p.user.institution <> null
  • SELECT p FROM PostDAO p WHERE true OR p.user.institution.id = 1

相关实体类定义

PostDAO

@Entity
@Table(name = "posts")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class PostDAO {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "date", nullable = false)
    private Date date;

    @Column(name = "expiration_date")
    private Date expirationDate;

    @Column(name = "text", columnDefinition = "TEXT")
    private String text;

    @ManyToOne
    @JoinColumn(name="user_id", nullable=false)
    private UserDAO user;
}

UserDAO

@Data
@Entity
@Table(name = "users", uniqueConstraints = {
        @UniqueConstraint(columnNames = {"login"})
})
public class UserDAO {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @Column(name = "login")
    private String login;
    @Column(name = "password")
    private String password;

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "user")
    private CompanyDAO company;

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "user")
    private InstitutionDAO institution;

    @ManyToMany
    @JoinTable(
            name = "users_roles",
            joinColumns = @JoinColumn(
                    name = "user_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(
                    name = "role_id", referencedColumnName = "id"))
    private Set<RoleDAO> roles;
}

问题原因

JPA在处理关联属性访问(如p.user.institution)时,默认会生成内连接(INNER JOIN)。内连接会自动过滤掉关联对象为NULL的记录——也就是当用户的institution为NULL时,这部分Post会被内连接提前排除,后续的WHERE条件(true OR ...)根本无法作用于这些被过滤掉的数据。

解决方法

方法一:显式使用左连接(LEFT JOIN)

通过显式左连接,确保即使user.institution为NULL,对应的Post记录也能被保留。修改后的JPQL:

@Query("SELECT p FROM PostDAO p LEFT JOIN p.user u LEFT JOIN u.institution i WHERE true OR i IS NOT NULL")

如果核心需求就是返回所有Post记录,可简化为:

@Query("SELECT p FROM PostDAO p LEFT JOIN p.user u LEFT JOIN u.institution i")

方法二:直接移除不必要的关联查询条件

既然预期是返回所有Post记录,完全可以去掉WHERE子句中对user.institution的引用,直接使用最基础的查询:

@Query("SELECT p FROM PostDAO p")

或保留无意义但不影响结果的WHERE true:

@Query("SELECT p FROM PostDAO p WHERE true")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 22:32:57