August 15, 2021
Spring Data, Hibernate: Пересечение множеств и запрос во вложенные параметры
Есть сущности (показаны базовые поля):
ApplicationUser
@Entity
@Table(name = "application_user")
@Data
public class ApplicationUser {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
@SequenceGenerator(name = "sequenceGenerator")
private Long id;
@Column(name = "is_active")
private Boolean isActive;
@Column(name = "second_name")
private String secondName;
@OneToOne(fetch = FetchType.EAGER)
@JoinColumn(unique = true)
private User user;
}User
@Entity
@Table(name = "sys_user")
@Data
public class User {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
@SequenceGenerator(name = "sequenceGenerator")
private Long id;
@NotNull
@Email
@Size(min = 5, max = 254)
@Column(name = "email", length = 254, unique = true, nullable = false)
private String email;
@ManyToMany
@JoinTable(
name = "sys_user_authority",
joinColumns = { @JoinColumn(name = "user_id", referencedColumnName = "id") },
inverseJoinColumns = { @JoinColumn(name = "authority_name", referencedColumnName = "name") }
)
@BatchSize(size = 20)
private Set<Authority> authorities = new HashSet<>();
}Authority
@Entity
@Table(name = "authority")
@Data
public class Authority {
@NotNull
@Size(max = 50)
@Id
@Column(length = 50)
private String name;
}Требуется вывести всех активных пользователей (ApplicationUser) в режиме Pageable, которые принадлежат определённым ролям (Authority).
Первый вариант:
Page<ApplicationUser> findAllByIsActiveIsTrueAndUser_AuthoritiesIsIn(Set<Authority> authorities, Pageable pageable);
Работает, но выводятся дубли (по кол-ву совпавших у пользователя ролей).
Второй вариант:
@Query(
value = "select distinct applicationUser from ApplicationUser applicationUser left join fetch applicationUser.user, Authority a " +
"where a in (:authorities) and a in elements(applicationUser.user.authorities) and applicationUser.isActive = true",
countQuery = "select distinct applicationUser from ApplicationUser applicationUser, Authority a " +
"where a in (:authorities) and a in elements(applicationUser.user.authorities) and applicationUser.isActive = true"
)
Page<ApplicationUser> findAllByIsActiveIsTrueAndUser_AuthoritiesIsIn(Set<Authority> authorities, Pageable pageable);Всё работает. Для сравнения множеств в раздел from дополнительно указываем Authority, а в where сравниваем authority с искомым списком ролей, а затем с ролями пользователя и делаем distinct.
Вариант findDistinctByIsActiveIsTrueAndUser_AuthoritiesIsIn для вложенных запросов не сработал, но должен работать для обычных запросов.