如何解决Spring Data中的分页+ @Query + JOIN获取?不起作用
我正在尝试使用Spring Data中的Pageable
批注将排序字段上的@Query
集成到一起。
第一个接口的方法(不带@Query
但带Pageable
)的作用就像是一个超级按钮。就像当我仅使用@Query
来获取一名Employee时一样,但是我使用的是Pageable
而不是Optional<Employee>
(第3种方法)。 但是 当我尝试将这两者合而为一时,乐趣就开始了。
当我尝试按name
字段对数据进行排序时,它会发出以下错误消息:
Caused by: org.hibernate.QueryException: could not resolve property: name of: (....).model.employee.Employee
所以问题是:如何告诉spring在联接字段中寻找name
?如何使用Spring Data做到这一点?
我已经尝试了几种方法,但是它们没有起作用,或者我仍然不知道如何正确使用它们:
- 有人建议将
countQuery
添加到@Query
参数中,以便在某种程度上与分页(spring data jpa @query and pageable)相符 - 我已关注Baeldung's tutorial,但这并不涵盖联接
- Spring-Data FETCH JOIN with Paging is not working也建议使用
countQuery
,但我宁愿坚持使用Page<Employee>
而不是List<Employee>
。
我将在下面留下一些代码示例。如果我省略了一些重要的内容,请随时要求更新。
// 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,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,String sortColumn) {
Page<EmployeeDTO> employeePage = employeeRepository.getEmployeeDetails(status,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();
}
// ...
}
编辑:
这是我的rest控制器的方法之一:
@GetMapping
public ResponseEntity<EmployeeResponse> getEmployeesByStatus(EmployeeStatus status,String sortDirection,String sortColumn) {
try {
EmployeeResponse employeeResponse = employeeService.getEmployeesByStatus(status,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();
}
}
解决方法
尝试下面的代码。
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);
在这里,我们试图通知JPA该名称是Employee表的外键。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。