如何从实体集合中对属性中的实体列表进行排序

时间:2018-11-28 14:18:57

标签: java sorting spring-boot spring-data-jpa

我有一个实体Mission,它有一个实体Trip的集合,并且我希望能够根据Trip集合中的内容对任务进行排序。

Trip实体:

@Entity
public Class Trip {
    @Id private Long id;
    @Column private LocalDateTime time;
}

Mission实体:

@Entity
public Class Mission {
    @Id private Long id;
    @Column private String city;
    @OneToMany(mappedBy = "mission")
    private Collection<Trip> trips;
}

Mission存储库:

@Repository
public interface MissionRepository extends PagingAndSortingRepository<Mission, Long>, QuerydslPredicateExecutor<Mission>, QuerydslBinderCustomizer<QMission> {

    @Override
    default void customize(final QuerydslBindings bindings, final QMission mission) {
        bindings.bind(String.class).first((final StringPath path, final String value) -> path.containsIgnoreCase(value));
        bindings.including(mission.city);
        bindings.excludeUnlistedProperties(true);
    }

    Page<T> findAll(Predicate predicate, Pageable pageable);
}

Mission服务:

@Service
@Transactional
public class MissionService {

    private final MissionRepository missionRepository;

    @Autowired
    public MissionService(final MissionRepository missionRepository) {
        this.missionRepository = missionRepository;
    }

    public Page<Mission> findAll(final Predicate predicate, final Pageable pageable) {
        return this.missionRepository.findAll(predicate, pageable);
    }
}

Mission控制器:

@RestController
@RequestMapping("/api/missions")
public class MissionController {

    private final MissionService missionService;

    @Autowired
    public MissionController(final MissionService missionService) {
        this.missionService = missionService;
    }

    @GetMapping
    @ResponseBody
    public Page<Mission> getAllMissions(@QuerydslPredicate(root = Mission.class) final Predicate predicate, @PageableDefault final Pageable pageable) {
        return this.missionService.findAll(predicate, pageable);
    }
}

调用/api/missions?sort=city,DESC时,它可以正常工作。 但是,在致电/api/missions?sort=trips.time,DESC时,我得到的重复条目与与任务链接的旅程次数相匹配。 所有这些任务都已正确排序,但重复的部分只是不可行……

目标是能够根据Mission集合中的出发日期对ASCDESCTrip)进行排序(这将是第一个TripASC中排序。)

那么,如何在Mission集合中的内容上对Trip的此列表进行排序,而无需获取重复部分呢?

如果可能的话,我也希望避免更改REST方法签名或数据库结构。

我本来打算在列表中添加DISTINCT,但是由于排序需要在第一个Trip的时间字段中进行,因此无法正常工作。可以在ASC模式下进行排序。但是在DESC中,它将根据到达日期而不是出发日期进行排序...

一个疯狂的想法:是否有可能自动使用查询的内容填充任务中的瞬时属性,然后使用Pageable类对其进行排序?

1 个答案:

答案 0 :(得分:0)

1 –首选

我可以使用Hibernate的@Formula注释解决问题。

1.1 –在Mission实体内添加以下属性

@Formula("(select min(t.time) from Trip t where t.mission_id = id)")
private LocalDateTime startDate;

1.2 –按属性排序

我们只需要调用属性即可。

/api/missions?sort=startDate,DESC


2 –第二个选择

目前,我没有任何性能问题。 但是,以防万一,我还考虑使用一个视图,然后将其链接到我的实体。

注意:这不是一个测试,但基于我对以下blog的理解。

2.1 –基于表TripMission

创建视图
CREATE OR REPLACE VIEW mission_derived AS
select 
  m.`id` as id,
  min(t.`time`) as startDate
from `trip` t
inner join `mission` m on t.`mission_id` = m.`id`
group by m.`id`;

2.2 –创建与此视图匹配的Java实体

@Entity
@Immutable
public class MissionDerived {

  @Id
  private long id;

  @Column
  private Date startDate;

}

2.3 –将属性添加到我的Mission实体

@OneToOne
@PrimaryKeyJoinColumn(name="ID")
private MissionDerived derived;

2.4 –使用此属性进行排序

然后,我们需要从任务中调用属性,然后从派生实体中调用属性。

/api/missions?sort=derived.startDate,DESC