当前位置: 首页 > 知识库问答 >
问题:

用Spring Data JPA进行复杂排序

慕容超
2023-03-14
@Entity
public class Message extends AbstractVersionedEntity {
    @OneToMany
    private Set<MessageOwner> messageOwners = new HashSet<>();
}

@Entity
public class MessageOwner extends AbstractVersionedEntity  {        
    @ManyToOne
    private Mailbox owner;

    @Enumerated(EnumType.STRING)
    private MessageOwnerType type;
}

@Entity
public class Mailbox extends AbstractVersionedEntity {        
    @Column(unique=true)
    private String ldapId;
}
message->messageOwners(type=TO)->owner->ldapId

此外,应该对每个邮件的收件人进行排序--如果有多个类型为MessageOwnerType.to的messageOwner,那么应该按字母顺序选择第一个作为邮件的排序值。

在纯SQL中,我可能会使用某种子查询来完成此操作。使用Spring数据规范&Sort Object有类似的可能吗?除非迫不得已,否则我宁愿不必重写QueryDSL/RAW标准中的所有内容。

共有1个答案

昌正奇
2023-03-14

好吧,所以我想出了如何使用规范来完成它,但这并不漂亮。我不能使用Sort对象,而是使用JPA CriteriaBuilder将orderBy子句放在规范中。

在tern中,这导致了SimpleJpaRepository的问题,它在所有可分页的findAll查询之前执行select count()。我不得不禁用这个(在这个Stackoverflow回答的帮助下)。

所以我的说明是这样的:(我知道,很讨厌。如果有人有更好的建议,我很乐意听到。)

@Override public Predicate toPredicate(Root<Message> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
    // Note - this would be simpler if JPA allowed subqueries in joins. As it doesn't,
    // we have to put the subquery in a where clause, join both sides with the mailbox
    // and correlate the results

    // join the main query on the mailbox (for the ORDER BY clause)
    Join<Message, MessageOwner> messageOwners = root.join("messageOwners", JoinType.LEFT);
    Join<Message, Mailbox> mailbox = messageOwners.join("owner");

    // create a subquery and correlate the messages with the main query
    Subquery<String> subQuery = query.subquery(String.class);
    Root<Message> sqMessage = subQuery.from(Message.class);
    Root<Message> correlateMessage = subQuery.correlate(root);

    // join the subquery on the mailbox
    Join<Object, Object> sqMessageOwners = sqMessage.join("messageOwners", JoinType.LEFT);
    Join<Message, Mailbox> sqMailbox = sqMessageOwners.join("owner");

    // get the lowest ldapId alphabetically 
    Expression<String> minLdapId = cb.least(sqMailbox.<String>get("ldapId"));

    // the actual subquery
    // select the lowest ldapId for the current message (see the group-by clause)
    // where the recipient type is TO and the message is the same as the main query
    subQuery.select(minLdapId)  
            .where(
                    cb.and(     
                            cb.equal(sqMessageOwners.get("type"), MessageOwnerType.TO),
                            cb.equal(sqMessage, correlateMessage)))
            .groupBy(sqMessage.get("id")); 

    // the subquery gives us the lowest TO recipient for each mail
    // sort on these values. Note: his must be done here rather than in the Sort property
    // of the Pageable in order to maintain the connection between the mailbox in the order by clause
    // and the one in the subquery
    Path<String> recipientOrderClause = mailbox.get("ldapId");
    Order recipientOrder = sortDirection == Sort.Direction.ASC ? cb.asc(recipientOrderClause) : cb.desc(recipientOrderClause);

    // secondary sorting descending by sendTime
    Order sendTimeOrder = cb.desc(root.get("sendTime"));

    // adding order by queries here, rather than via the Sort object
    // is something of a violation of standard Spring Data practice. (see above for the reason it is done)
    // this precludes us from making some grouped calls such as select count(*)
    query.orderBy(recipientOrder, sendTimeOrder);

    // attach the subquery onto the query and return.
    return cb.equal(mailbox.get("ldapId"), subQuery);
}
 类似资料:
  • 下面是数组上HEAPSORT的伪代码 很明显,BUILD-MAX-HEAP的复杂度为O(n),MAX-HEAPIFY的复杂度为O(h),其中h是具有最大logn值的堆的高度。 我不完全理解的是为什么HeapSort有nlogn的复杂性。我知道我们有n次迭代,每次迭代都有一个MAX-HEAPIFY。但是他MAX-HEAPIFY调用在每次迭代中都得到一个大小递减的HEAP。那么为什么每次迭代都有O(l

  • 我有下表在OracleSQL方言(被调用与一些java代码) 我正在寻找一种方法来进行以下分类: 将part、locker、serial#组合在一起,并在每个组内按升序或降序对描述进行排序,同时确保每个组的第一条记录也按升序或降序正确排序(冲突应按part、locker、serial的所需顺序排序)。例如: 排序DESC将产生: 如何实现这种复杂的排序类型?仅仅通过查询就可以吗?

  • 例如,我有简单的DF: 我是否可以使用熊猫的方法和习惯用法,从“A”中选择“B”对应值大于50的值,以及“C”对应值不等于900的值?

  • 问题内容: Python的复杂性是什么?Python是否检查给定的iterable是否已排序,还是我必须自己做?我在文档中的任何地方都找不到它。 问题答案: 这 完全 取决于实现。python保证的是内置排序算法是 稳定的 (比较相等的元素保留其相对顺序)。如果要实现,甚至可以使用稳定的冒泡排序。 Cpython使用TimSort(插入排序的合并排序合并),如果输入已经排序,我相信它具有O(N)的

  • 类似于这样: 对Docker来说这可能吗?

  • 所以我遇到了这个方法,它能够按值对HashMaps进行排序。 我想在比较器上使用方法,但是我似乎找不到合适的地方放它。