首页 > 解决方案 > 当关系为空时,JPA 规范不起作用

问题描述

我正在实现基于两个实体的搜索。

@Entity(name = "user")
public class UserEntity {
    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    @Column(updatable = false, nullable = false)
    private String id;
    @Column(unique = true, nullable = false)
    private String email;
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "foo_id", referencedColumnName = "id")
    private FooEntity foo;
    private UserType type;
}

@Entity(name = "foo")
public class FooEntity {
    @Id
    @GeneratedValue(generator="system-uuid")
    @GenericGenerator(name="system-uuid", strategy = "uuid")
    @Column(updatable = false, nullable = false)
    private String id;
    private String identifier;
}

现在我想根据电子邮件地址查找用户,或者当 FooEntity 关系基于该关系中的标识符存在时。AND 基于 UserEntity 中的枚举类型。

我尝试了以下查询:

public static Specification<UserEntity> emailLike(String text) {
     return (root, query, criteriaBuilder) -> criteriaBuilder.like(root.get("email"), "%" + text + "%");
    }
    
public static Specification<UserEntity> patientIdentifier(String text) {
      return (root, query, criteriaBuilder) -> criteriaBuilder.like(root.join("foo").get("identifier"), "%" + text + "%");
    }
public static Specification<UserEntity> userType(UserType type) {
            return (root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("type"), type);
        }
    
final Specification<UserEntity> specification = Specification.where(
                UserSpecification.patientIdentifier(text)
                        .or(UserSpecification.emailLike(text))
        ).and(
                UserSpecification.userType(type)
        );
    
final Page<UserEntity> userEntities = userRepository.findAll(specification, pageable);

现在,当与 FooEntity 的关系存在时,此查询似乎有效。当此关系为 null 时,即使电子邮件和类型匹配,也不会返回任何内容。

有人可以帮我吗?

标签: javaspring-bootjpa

解决方案


你不应该只是加入,而是左加入或右加入。联接是内部联接,这意味着它只匹配符合联接条件的记录。在 SQL 中任何等于 null 的东西总是假的,所以我希望任何一个连接站点都为 null,记录不在结果集中。因此,左连接表示,响应所有左站点实体并仅在存在时匹配右站点,如果不存在,则右站点为空。

所以加入应该看起来像root.join("foo", JoinType.LEFT)(未经测试)


推荐阅读