Я реализую поиск на основе двух сущностей.
@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 существует на основе идентификатора в этом отношении. И на основе типа перечисления в 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, ничего не возвращается, даже если адрес электронной почты и тип совпадают.
Кто-нибудь может мне помочь?




Вы должны не просто присоединиться, а присоединиться к левой или правой стороне. Соединение — это внутреннее соединение, которое означает, что оно соответствует только записям, которые соответствуют критериям соединения. Все, что равно нулю в SQL, всегда является ложным, поэтому я бы предпочел, чтобы любой из сайтов присоединения был нулевым, а запись отсутствует в наборе результатов. Таким образом, левое соединение говорит: отвечайте всеми объектами левого сайта и сопоставляйте правильный сайт, только если он присутствует, если не правый сайт, имеет значение null.
Таким образом, объединение должно выглядеть как root.join("foo", JoinType.LEFT) (не проверено)
Большое спасибо. Упускал из виду это. Это действительно левое соединение.