[英]Pageable + @Query + JOIN (fetch?) in Spring Data don't work
I'm trying to integrate sorting with Pageable
on joined fields with the use of @Query
annotation from Spring Data.我正在尝试使用来自 Spring 数据的@Query
注释在连接字段上将排序与Pageable
集成。
1st interface's method (without @Query
but with the Pageable
) works like a charm.第一个接口的方法(没有@Query
但有Pageable
)就像一个魅力。 Same like when I'm fetching only one Employee with the @Query
but instead of Pageable
I'm using Optional<Employee>
there (3rd method).就像当我只使用@Query
获取一个 Employee 但不是Pageable
我在那里使用Optional<Employee>
(第三种方法)时一样。 But the fun begins when I try to put these two all together in one - it won't work anymore.但是,当我尝试将这两者合而为一时,乐趣就开始了——它不再起作用了。
When I try to sort the data by name
field it screams with this error:当我尝试按name
字段对数据进行排序时,它会出现以下错误:
Caused by: org.hibernate.QueryException: could not resolve property: name of: (....).model.employee.Employee
So the question is: how to tell spring to look for name
in joined fields ?所以问题是:如何告诉 spring 在连接字段中查找name
? How to do this with Spring Data?如何使用 Spring 数据执行此操作?
I've already tried several things but they didn't work or I still don't know how to use them properly:我已经尝试了几件事,但它们没有用,或者我仍然不知道如何正确使用它们:
countQuery
to the @Query
parameters so this corresponds somehow with the pagination ( spring data jpa @query and pageable )有人建议将countQuery
添加到@Query
参数中,这样这在某种程度上与分页相对应( spring 数据 jpa @query 和可分页)countQuery
but I'd prefer to stick to Page<Employee>
rather than List<Employee>
. Spring-Data FETCH JOIN with Paging is not working也建议使用countQuery
但我更愿意坚持使用Page<Employee>
而不是List<Employee>
。I'll leave some samples of the code below.我将在下面留下一些代码示例。 Feel free to ask for update if I omitted something important.如果我遗漏了一些重要的东西,请随时要求更新。
// Employee
@Entity
@Table(name = "employee", schema = "emp")
@Data
@NoArgsConstructor
public class Employee {
private static final String SEQUENCE = "EMPLOYEE_SEQUENCE";
@Id
@SequenceGenerator(sequenceName = SEQUENCE, name = SEQUENCE, allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQUENCE)
private Long id;
@Column(name = "employee_number")
private String employeeNumber;
@Column
@Enumerated(EnumType.STRING)
private EmployeeStatus status;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
@JoinColumn(name = "id_details")
private Details details;
// some other fields ...
}
// Details
@Entity
@Table(name = "details", schema = "emp")
@Data
@NoArgsConstructor
public class Details {
private static final String SEQUENCE = "DETAILS_SEQUENCE";
@Id
@SequenceGenerator(sequenceName = SEQUENCE, name = SEQUENCE, allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQUENCE)
private Long id;
private String name;
private String surname;
// some other fields ...
}
// EmployeeDTO
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder(toBuilder = true)
public class EmployeeDTO {
private Long id;
private String employeeNumber;
private String status;
private String name;
private String surname;
// some other fields ...
}
// EmployeeRepository
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
// 1st method
Page<Employee> findByStatus(EmployeeStatus status, Pageable pageable);
// 2nd method
@Query(value = "select e from Employee e join e.details where e.status = :status",
countQuery = "select count(*) from Employee e join e.details where e.status = :status")
Page<Employee> getEmployeeDetails(@Param("status") EmployeeStatus status, Pageable pageable);
// 3rd method
@Query("select e from Employee e join fetch e.details where e.id = :id")
Optional<Employee> findByIdWithDetails(Long id);
// ...
}
// EmployeeService
@Service
public class EmployeeService {
private final EmployeeRepository employeeRepository;
private final EntityDtoConverter entityDtoConverter;
@Autowired
public EmployeeService(EmployeeRepository employeeRepository, EntityDtoConverter entityDtoConverter) {
this.employeeRepository = employeeRepository;
this.entityDtoConverter = entityDtoConverter;
}
public EmployeeResponse getEmployeesByStatus(EmployeeStatus status, int pageSize, int pageIndex, Sort.Direction sortDirection, String sortColumn) {
Page<EmployeeDTO> employeePage = employeeRepository.findByStatus(status, PageRequest.of(pageIndex, pageSize, Sort.by(sortDirection, sortColumn)))
.map(entityDtoConverter::convertEmployeeBaseToDto);
return new EmployeeResponse(employeePage);
}
public EmployeeResponse getEmployeeDetails(EmployeeStatus status, int pageSize, int pageIndex, Sort.Direction sortDirection, String sortColumn) {
Page<EmployeeDTO> employeePage = employeeRepository.getEmployeeDetails(status, PageRequest.of(pageIndex, pageSize, Sort.by(sortDirection, sortColumn)))
.map(entityDtoConverter::convertToEmployeeWithDetailsDto);
return new EmployeeResponse(employeePage);
}
// ...
}
// EntityDtoConverter
@Component
public class EntityDtoConverter {
public EmployeeDTO convertEmployeeBaseToDto(Employee entity) {
return EmployeeDTO.builder()
.id(entity.getId())
.employeeNumber(entity.getEmployeeNumber())
.status(entity.getStatus())
.build();
}
public EmployeeDTO convertToEmployeeWithDetailsDto(Employee entity) {
return convertEmployeeBaseToDto(entity).toBuilder()
.name(entity.getDetails().getName())
.surname(entity.getDetails().getSurname())
.build();
}
// ...
}
This is one of the methods of my rest controller:这是我的rest controller的方法之一:
@GetMapping
public ResponseEntity<EmployeeResponse> getEmployeesByStatus(EmployeeStatus status, int pageSize, int pageIndex, String sortDirection, String sortColumn) {
try {
EmployeeResponse employeeResponse = employeeService.getEmployeesByStatus(status, pageSize, pageIndex, Sort.Direction.fromString(sortDirection), sortColumn);
return employeeResponse.getTotalElements().equals(0L) ? ResponseEntity.noContent().build() : ResponseEntity.ok(employeeResponse);
} catch (Exception e) {
log.error(ERROR_MESSAGE, e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
Try below code.试试下面的代码。
Specification<Employee> joins = (employee, query, cb) -> {
Join<Employee, Detail> details = employee.join("details");
return cb.and(
employee.equal(employee.get("name", name)),
details.equal(details.get("name", detailName))
);
};
PageRequest pageRequest = new PageRequest(0, 2, new Sort(Sort.Direction.DESC, "name"));
Page<Employee> customerPage = employeeRepository.findAll(joins, pageRequest);
Here we are trying to inform JPA that this name is foreign key for Employee table.这里我们试图通知 JPA 这个名字是 Employee 表的外键。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.