Я делаю тренировочное приложение Spring Boot.
У меня есть 3 объекта (отредактировано в соответствии с рекомендациями):
class User extends EntityModelTemplate {
String username; //unique
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
List<UserRoles> userRoles;
}
@IdClass(UserRolesKey.class)
class UserRoles {
@Id
@ManyToOne
@JoinColumn(name = "user_id")
User user;
@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "role_id")
Role role;
}
class Role extends EntityModelTemplate{
String role;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "role")
List<UserRoles> userRoles;
}
Я хотел сделать сингл вызов БД, который выбирает пользователя вместе с ролями, поэтому я попытался использовать спецификации. Я прочитал документацию и искал примеры в Интернете, прежде чем придумал что-то, что должно работать так, как я хотел.
Метод обслуживания (отредактированный в соответствии с рекомендациями):
public UserDTO getUserForSecurityCheck(String username) throws UsernameNotFoundException {
log.info("Repository call start!");
Optional<User> user = userRepo.findOne(Specification.where(UserSpecifications.usernameEquals(username)));
log.info("Repository call end!");
return user.map(UserDTO::new).orElseThrow(() -> new UsernameNotFoundException("Username "+username+" not found!"));
}
Спецификация:
public static Specification<User> usernameEquals(String username){
return (root, query, criteriaBuilder) -> {
( (Join<Object, Object>) root.fetch(User_.USER_ROLES)).fetch(UserRoles_.ROLE);
return criteriaBuilder.equal(root.get(User_.USERNAME), username);
};
}
Он отлично работает, за исключением того, что Hibernate делает два вызова БД.
(правка)
Первый выбирает все, что нужно, используя два объединения, где username =? (это довольно долго, следовательно, короткая, короткая версия). Именно это я и хотел. Но затем он делает второй вызов, который буквально делает Select * (кроме userRoles) от пользователя, где user_id =?.
Почему?
Хотя я все еще новичок в кодировании в целом, Я был почти уверен, что понял, как работают Спецификация и Hibernate. Основы, по крайней мере. Очевидно, что нет.
Итак, мой вопрос: предполагается ли сделать два вызова БД или что я делаю не так?
Заранее спасибо.