如何在 Room 中查询复杂的嵌套对象?

How to query a complex nested objects in Room?

我有几个实体,您可以在下面看到,问题是当您有多于一层的嵌套时如何正确 select 嵌套列表。如果您查看 github, you can find very simple example, but not something complex. As documentation says here 上的 Google 存储库,Room 不允许对象引用。如何获得 ResultObject(以及它的外观)包括所有嵌套列表?

ResultObject 应该有这个信息:

  1. List<Dialog>
  2. Dialog 实体有 List<Message>
  3. MessageList<ImageContent>.
  4. ImageContentList<ImageContentItem>

对话框

@Entity(tableName = "dialog")
data class Dialog(@PrimaryKey val id String, val title: String)

留言

@Entity(tableName = "message",
        foreignKeys = [(ForeignKey(entity = Dialog::class, parentColumns ["id"], childColumns = ["dialogId"]))])
data class Message(@PrimaryKey val id: String, val dialogId: String)

图片内容

@Entity(tableName = "image_content",
        foreignKeys = [(ForeignKey(entity = Message::class, parentColumns = ["id"], childColumns = ["messageId"]))])
data class ImageContent(@PrimaryKey val id: String, val messageId: String)

ImageContentItem

@Entity(tableName = "image_content_item",
        foreignKeys = [(ForeignKey(entity = ImageContent::class, parentColumns = ["id"], childColumns = ["imageContentId"]))])
data class ImageContentItem(val imageContentId: String,
                        @PrimaryKey(autoGenerate = true) val id: Long = 1)

道:

@Dao
interface DialogDao {
    @Query("SELECT * FROM dialog " +
            "INNER JOIN message ON message.dialogId = dialog.id " +
            "INNER JOIN image_content ON image_content.messageId = message.id " +
            "INNER JOIN image_content_item ON image_content_item.imageContentId = image_content.id")
    fun getDialogAllInformation(): Flowable<List<**ResultObject**>>
}

Rooms 与 entity/table 一起使用,它不允许按您的需要管理结构化对象。您唯一可以做的就是单独执行查询,然后构建您的 ResultObject.

您可以根据需要嵌套 类 定义关系。

class DeepDialog {
    @Embedded lateinit var embedded: Dialog

    @Relation(parentColumn = "id", entityColumn = "dialogId", entity = Message::class)
    lateinit var messages: List<DeepMessage>
}

class DeepMessage {
    @Embedded lateinit var embedded: Message    

    @Relation(parentColumn = "id", entityColumn = "messageId", entity = ImageContent::class)
    lateinit var imageContents: List<DeepImageContent>
}

... etc

我认为 Room guys 应该提供更优雅的东西,因为这个解决方案至少有两个问题。

  1. 它引入了非常烦人的样板文件。
  2. @Relation 注释只能用在列表或集合上,因此它不涵盖您有 1:1 关系的场景。

想象一下,根据定义,您的 Dialog 只有一个 Message(而不是很多)。在这种情况下,您不希望 DeepDialog 具有 messages: List<> 访问器,而是 message: Message。我发现的唯一方法是:

class DeepDialog {
    @Embedded lateinit var embedded: Dialog

    @Relation(parentColumn = "id", entityColumn = "dialogId", entity = Message::class)
    internal lateinit var messages: List<DeepMessage>
    val message get() = messages.firstOrNull()
}