PlayFramework - 按 OneToMany 关系的最后一个条目排序的页面

PlayFramework - Page Sort by last Entry of OneToMany Relationship

我有以下结构:

public class ConversationModel extends Model {

    @Id
    public Long id;

    @OneToMany(mappedBy="conversation", cascade= CascadeType.ALL)
    public List<EventModel> events;

}

public abstract class EventModel extends Model {

    @Id
    public Long id;
    public Date time;

}

现在,当我从对话模型中获取页面时,我想按数组事件中 EventModel 的最新条目对它们进行排序。

我试过类似的东西:

            return find.where().disjunction()
                .add(Expr.ilike("name", "%" + filter + "%"))
                ...
                .orderBy("events.time desc, " + sortBy + " " + order)
                .findPagedList(page, pageSize);

但这不知何故 returns 每个事件的分页列表中的 ConversationModel 条目。 (例如,如果有 3 个事件,则同一个对话重复 3 次) 如果我在 orderBy 查询中省略 "events desc",我会得到想要的结果,但排序不正确。

我也尝试在查询中设置 .setDistinct(true),但是 returns "Invalid SQL Syntax".

如何将我的所有对话排序到他们的最新事件条目?

感谢您的帮助。

编辑:

我设置了一个示例项目,它显示了问题:

https://github.com/dominik-ziegler/play-page-sort

应用程序首次启动时将对话打印到控制台:

[debug] - application - Conversation: First Conversation; ID1
[debug] - application - Conversation Last Message: Tue Jan 12 23:03:55 CET 2016
[debug] - application - ----------
[debug] - application - ----------
[debug] - application - Conversation: Second Conversation; ID2
[debug] - application - Conversation Last Message: Tue Jan 12 23:03:55 CET 2016
[debug] - application - ----------
[debug] - application - ----------
[debug] - application - Conversation: Third Conversation; ID3
[debug] - application - Conversation Last Message: Tue Jan 12 23:03:55 CET 2016
[debug] - application - ----------

但是根据插入日期顺序应该是:

  1. 第二次对话
  2. 第三次对话
  3. 第一次对话

在您的 ConversationModel 中,您可以使用 @javax.persistence.OrderBy 注释该字段,即:

@OneToMany(mappedBy="conversation", cascade= CascadeType.ALL)
@OrderBy("time DESC")
public List<EventModel> events;

它会做你需要的事情 - 将根据你的意愿对事件进行排序,而无需触及主要排序(因此你可以在查找查询中为对话添加其他排序)。

编辑:要实现您想要的效果,您需要使用
执行查询 GROUP BY conversation.idORDER BY event.id

(MySQL伪代码):

SELECT c.id c0, e.id FROM conversation c 
    LEFT OUTER JOIN event e ON c.id = e.conversation_id 
    WHERE lower(c.name) LIKE '%foo%'
    GROUP BY c.id
    ORDER BY e.id DESC;

不幸的是,裸露的 Finder 不允许您这样做,但您可以使用自己的 WHERE 构建 PagedList 并添加分组,例如:

PagedList<ConversationModel> convsPage = Ebean
     .createQuery(
         ConversationModel.class, 
         "WHERE lower(name) like :search GROUP BY id"
     )
     .setParameter("search","%"+filter+"%")
     .order("events.id DESC")
     .findPagedList(page, pageSize);