首页 > 解决方案 > 具有 2 个实体的数据类混淆列

问题描述

我在 Android 应用程序的房间数据库中有两个实体。这个概念是每个站点都有许多组。

@Entity(tableName = "sites")
data class Site(

    @ColumnInfo(name = "server_id")
    var serverId: Long,

    @PrimaryKey
    @ColumnInfo(name = "site_id")
    val siteId: Int,

    @ColumnInfo(name = "description", defaultValue = "")
    val description: String

)


@Entity(tableName = "groups")
data class Group(

    @ColumnInfo(name = "server_id")
    val serverId: Long,

    @PrimaryKey
    @ColumnInfo(name = "group_id")
    var groupId: Int,

    @ColumnInfo(name = "site_id")
    val siteId: Int,

    @ColumnInfo(name = "description", defaultValue = "")
    val description: String

) 

所以我想给一个siteId和一个groupId,两个从数据库中获取一个名为SiteWithGroup的POJO,它是

data class SiteWithGroup(
    @Embedded
    val site: Site,

    @Relation(parentColumn = "site_id", entityColumn = "site_id", entity = Group::class)
    val group: Group
)

我创建了一个 MediatorLiveData,它观察 siteId、groupId 并且当它同时具有这两者时,它会从 db 返回一个查询

private val siteGroupPair = MediatorLiveData<Pair<Int?, Int?>>().apply {
        addSource(siteId) {
            value = Pair(it, groupId.value)
        }
        addSource(groupId) {
            value = Pair(siteId.value, it)
        }
    }

    override val siteGroup: LiveData<SiteWithGroup>
        get() = Transformations.switchMap(siteGroupPair) {
            it?.let { pair ->
                if (pair.first != null && pair.second != null)
                    sitesRepository.siteWithGroup(pair.first!!, pair.second!!)
                else null
            }
        }



//Dao query
@Query("""Select * from groups
        inner join sites on groups.site_id = :siteId
        where sites.site_id = :siteId and groups.group_id = :groupId
    """)
    fun getByIdWithGroups(siteId: Int, groupId: Int): LiveData<SiteWithGroup>

如果我们假设 siteId, groupId = 1, 1 and i 在我的数据库中有以下条目

Group entity
serverId, groupId, siteId, description
1         1        1       "Group1 description"
1         2        1       "Group2 description"

________________________________________________

Site entity
serverId, siteId, description
1         1       "Site1 description"

我们期望结果是

SiteWithGroup(
   site=Site(serverId=1, siteId=1, description=Site1 description), 
   group=Group(serverId=1, groupId=2, siteId=1, description=Group2 description)
)

但是我们得到了这个

SiteWithGroup(
   site=Site(serverId=1, siteId=1, description= !!!<<Group1 description>>!!!), 
   group=Group(serverId=1, groupId=<<2>>, siteId=1, description= <<Group2 description>>)
)

站点实体得到组描述和错误的描述!!似乎根本没有应用组约束。这是怎么回事?我该如何解决?谢谢

但是在我的用户界面上,结果是

标签: androidkotlinandroid-roompojoandroid-room-relation

解决方案


您正在尝试与 混合join@Relation这会导致不可预测的结果。

请记住,@Relation第一步使用 Room 应用您给定的查询以从主实体 Site ( select * from sites ...) 获取数据,然后在第二步 - 启动另一个查询以附加第二个实体的 Group 数据(大致select * from groups where siteId IN <List of siteIds gotten after step1>)。因此,在第二个查询中,不再有任何条件group_id(并且由于查询是自动生成的,因此您无法在此处设置此条件)并且可能会拾取任何组(测试用例中的两个组中的任何一个)。

我想解决您可以替换实体SiteGroup数据类的问题:

data class SiteWithGroup(
    @Embedded
    val group: Group,

    @Relation(parentColumn = "site_id", entityColumn = "site_id")
    val site: Site
)

并且 dao 查询不应该包含任何 Join (它可以但它真的没用):

@Transaction
@Query("Select * from groups where site_id = :siteId and group_id = :groupId")
fun getByIdWithGroups(siteId: Int, groupId: Int): LiveData<SiteWithGroup>

推荐阅读