如何获取最近的关系项而不是 Android 房间中的列表

How to get the most recent relation item instead of a list in Android Room

我的结构如下:

包含一条或多条消息的对话。 Conversation 和 Message 都在各自的表中。 我创建了一个 ConversationDetailed 关系 POJO,将 Conversation 与其消息列表合并。

public class ConversationDetailed {

    @Embedded
    public Conversation conversation;

    @Relation(
        parentColumn = "id",
        entityColumn = "conversation_id",
        entity = Message.class
    )
    public List<Message> messageList;

}

到目前为止,这按预期工作,没有发现任何问题。 现在我正在尝试创建一个 ConversationSummary 关系,其中只有属于该对话的最新消息,我无法在任何地方找到如何执行此操作的示例。这就是我想要实现的目标:

public class ConversationSummary {

    @Embedded
    public Conversation conversation;

    @Relation(
        parentColumn = "id",
        entityColumn = "conversation_id",
        entity = Message.class
    )
    public Message recentMessage; // <- the most recent message of this conversation

}

我知道我可以使用 ConversationDetailed 并只从列表中选择最新的消息,但这意味着无需从数据库中查询大量消息,而我只需要最新的消息。

我怎样才能像上面的例子一样使用 Relation POJO 来实现这一点?

编辑:在尝试了另一个用户建议的初始答案后,我发现关系是单独的查询,这就是为什么使用 Relation POJO 的查询使用 Transaction 的原因,所以问题仍然没有答案。有没有办法指定关系项的顺序?

EDIT2:经过提供第一个答案的同一用户的详细解释后,我终于能够完成这项工作。这是适用于我的案例的基本原理。

MAX 与 JOIN 的组合允许我 select select 包含最新消息的对话,包括与该消息无关的所有对话。 为会话 ID 添加 GROUP BY 拆分上述逻辑以获得每个唯一会话 ID 的 MAX。 之后是将 ORDER BY 应用于消息创建日期的问题。

@Query(
    "SELECT " +
    "*, MAX(Message.date)" +
    "FROM Conversation " +
    "JOIN Message " +
    "ON Conversation.id = Message.conversation_id " +
    "GROUP BY Conversation.id " +
    "ORDER BY Message.date DESC "
)
abstract List<ConversationSummary> getSummaryList();

尝试下一个解决方法(因为我不知道只用 Relations 做你想做的事情的直接方法):

  1. 编写查询以获取对话中的所有最新消息。假设您有一些字段 posted 可用于定义消息是最近的(换句话说,您应该找到最大 posted 的详细对话)。
  2. 使用 Room RelationsConversation 实体附加到查询结果。

因此,附加 class(查询应 return 列表 Class 值):

public class RecentMessage {

    @Embedded
    public Message recentMessage;

    @Relation(
        parentColumn = "conversation_id",
        entityColumn = "id"
    )
    public Conversation conversation; 

}

并查询:

SELECT * FROM conversation_detailed as table1 JOIN (select conversation_id, max(posted) as posted from conversation_detailed) as table2 on table1.conversation_id=table2.conversation_id and table1.posted = table2.posted

@Relation 似乎从未被设计为考虑来自自定义@Query 的排序。这已在位于此处的与此问题相关的问题中得到确认:https://issuetracker.google.com/issues/128470264

第二好的选择是使用多个查询并手动构建返回的数据结构,按照链接问题中的建议。

对于我的情况,它将是两个表之间的 JOIN,按对话 ID 分组并按最新消息排在第一位。

想分享一个替代解决方案,一个我应用于我自己的相同问题的解决方案。您可以改为在对话中保存对最新消息的引用,确保正确编写,然后在您的关系中使用它。例如,您可以将“recent_message_id”添加到 Conversation,然后将其用于与“message_id”相关的特定消息。当然,这假设 Message 中有一个“message_id”。

public class ConversationSummary {

    @Embedded
    public Conversation conversation;

    @Relation(
        parentColumn = "recent_message_id",
        entityColumn = "message_id",
        entity = Message.class
    )
    public Message recentMessage;
}