简体   繁体   English

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

[英]How to sort a list of entities on the property from a collection of entities

I have an entity Mission which has a collection of entities Trip , and I would like to be able to sort the mission in function of the content in the collection of Trip . 我有一个实体Mission ,其中包含实体Trip的集合,并且我希望能够根据Trip集合中内容的功能对任务进行排序。

The Trip entity: Trip实体:

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

The Mission entity: Mission实体:

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

The Mission Repository: 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);
}

The Mission Service: 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);
    }
}

The Mission Controller: 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);
    }
}

When calling /api/missions?sort=city,DESC , it work perfectly. 调用/api/missions?sort=city,DESC ,它可以完美运行。 But when calling /api/missions?sort=trips.time,DESC I am getting duplicate entries which match the number of Trips linked with a Mission. 但是,当调用/api/missions?sort=trips.time,DESC我得到的重复条目与与任务链接的旅程次数相匹配。 All these mission are correctly sorted, but the duplicate part is just a no go… 所有这些任务均已正确排序,但重复的部分只是不可行的…

The objective is to be able to sort the Mission ( ASC or DESC ) in function of the departure date from the Trip collection (which would be the first Trip sorted in ASC ). 目的是能够根据Trip集合中的出发日期对MissionASCDESC )进行排序(这将是ASC排序的第一个Trip )。

So, how to sort this list of Mission on the content from the collection of Trip without getting the duplication part? 那么,如何在不包含重复部分的情况下,对Trip集合中的Mission列表进行排序呢?

I would also like to avoid changing the REST method signature or the database structure, if possible. 如果可能的话,我也想避免更改REST方法签名或数据库结构。

I was thinking of adding a DISTINCT on the list, but It wouldn't work as the sorting need to be on the first Trip's time field. 我当时正在考虑在列表中添加DISTINCT ,但是由于排序需要在第一个Trip的时间字段中进行,因此它不起作用。 Sorting in ASC mode would work. 可以在ASC模式下进行排序。 But in DESC , it would then be sorted in function of the arrival date, and not the departure… 但是在DESC ,它将根据到达日期而不是出发日期进行排序...

A crazy idea: would it be possible to automatically fill a transient property in the mission with the content of a query, and sort on it using the Pageable class? 一个疯狂的主意:是否有可能自动用查询的内容填充任务中的瞬时属性,然后使用Pageable类对其进行排序?

1 – First option 1 –首选

I was able to fix my problem by using the @Formula annotation from Hibernate. 我可以使用Hibernate的@Formula批注解决问题。

1.1 – Adding the following property inside the Mission entity 1.1 –在Mission实体内部添加以下属性

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

1.2 – Sorting on the property 1.2 –按属性排序

We just need to call the property. 我们只需要调用该属性。

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


2 – Second option 2 –第二种选择

Currently I don't have any performance issue. 目前,我没有任何性能问题。 Yet, just in case, I am also considering to use a view which will then be linked to my entity. 但是,以防万一,我还考虑使用将与我的实体链接的视图。

NB: This one wasn't test, but is based on my understanding from the following blog . NB:这不是测试,而是基于我对以下博客的了解。

2.1 – Create the view based on tables Trip and Mission 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 – Create the java entity matching this view 2.2 –创建与此视图匹配的Java实体

@Entity
@Immutable
public class MissionDerived {

  @Id
  private long id;

  @Column
  private Date startDate;

}

2.3 – Adding the property to my Mission entity 2.3 –将属性添加到我的Mission实体

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

2.4 – Sorting using this property 2.4 –使用此属性排序

We would then need to call the property from the mission, and then the property from the derived entity. 然后,我们需要从任务中调用属性,然后从派生实体中调用属性。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM