Android Room多对多交界处的桌子比2个桌子的关系更多

问题描述

我已经在User,Property和这两个项目UserPropertyJunction的联结表之间创建了一个关系,可以在下图中将其可视化为关联关系

enter image description here

UserEntity,而不是customers

@Entity(tableName = "user")
data class UserEntity(
    @PrimaryKey
    val userId: Long,val firstName: String,val lastName: String,val email: String,val password: String
)

属性,而不是products

@Entity(
    tableName = "property",primaryKeys = ["id"]
)
data class Property(
    val id: Int,val update: Int,val categoryId: Int,val title: String,val subject: String,val type: String,val typeId: Int
}

并连接表而不是product_helper

@Entity(
    tableName = "user_property_junction",primaryKeys = ["userAccountId","propertyId"],// Foreign Keys
    foreignKeys = [
        ForeignKey(
            entity = User::class,parentColumns = ["userId"],childColumns = ["userAccountId"],onDelete = ForeignKey.NO_ACTION
        ),ForeignKey(
            entity = Property::class,parentColumns = ["id"],childColumns = ["propertyId"],onDelete = ForeignKey.NO_ACTION
        )
    ]
)
data class UserPropertyJunction(
    val userAccountId: Long,val propertyId: Int
)

并使用

创建关系类
data class UserWithFavorites(

    @Embedded
    val user: User,@Relation(
        parentColumn = "userId",entity = Property::class,entityColumn = "id",associateBy = Junction(
            value = UserPropertyJunction::class,parentColumn = "userAccountId",entityColumn = "propertyId"
        )
    )
    val propertyList: List<Property>
)

还需要获取这些属性用户显示和喜欢多少次的数据。

为此,我们签出了解决方in this link,该解决方案向联结添加了其他字段,在我的示例中,添加displayCountfavorite属性

data class UserPropertyJunction(
    val userAccountId: Long,val propertyId: Int,val displayCount:Int=0,val favorite:Boolean=false
)

据我所知,我的第一个问题是对联结表或关联表没有太多的经验,它们仅存储应与之关联的表的外键,可以在联结表中添加值字段吗?

如果它不是很优雅或不是首选的方式,我应该添加一个与联结表有关系的表,例如

data class PropertyStatus(
    val userAccountId: Long,val favorite:Boolean=false
)

并关联他们?

当从用户属性属性状态两者中检索数据时,我应该手动从中获取数据

data class UserWithProperties(

    @Embedded
    val user: User,entityColumn = "propertyId"
        )
    )
    val propertyList: List<Property>
)

并根据您对第一个问题的答案从状态表或联结表中使用SELECT获取 或者可以通过UserWithProperties@Embedded

@Relation添加一个关系

解决方法

据我所知,不幸的是,没有开箱即用的方法,仅用Room的工具(@ Relation,@ Embedded,@ Junction)就可以解决用例。

据我所知,我的第一个问题是对联结表或关联表没有太多的经验,它们仅存储应与之关联的表的外键,可以在联结表中添加值字段吗?

问题是@Junction在使用中有一些限制-它仅有助于将两个表与保存在第三个(连接)表中的值绑定在一起。但是@Relation-with-@Junction API不支持从此联结表中获取要包含在结果类中的任何字段(这些外键仅用于绑定)。因此,从技术上讲,您可以向联结表中添加一些字段(似乎是保留这些值的最合适的地方),但是实际上,您无法使用@Junction获得这些字段。

也许可以使用一些破解方式,但是我的猜测-您必须使用SQL连接实现自己的方法,并通过循环传递结果以形成所需的结果(类似于在您在帖子中提到的链接)。

为简化起见,您可以按照您的建议真正描述实体连接表(但完全不要使用@Junction):

data class UserPropertyJunction(
    val userAccountId: Long,val propertyId: Int,val displayCount:Int=0,val favorite:Boolean=false
)

,然后添加辅助类(不是实体)并将其用作查询结果:

data class UserWithFavorites(
    val displayCount:Int,val favorite:Boolean,@Relation(
         parentColumn = "userAccountId",entityColumn = "userId"
    )
    val user: UserEntity,@Relation(
         parentColumn = "propertyId",entityColumn = "id"
    )
    val property: Property,)

当然,这不是您想要的,但至少您可以处理,它是开箱即用的,您可以将其与LiveData / Flow / RxJava一起使用(例如,在获得此权限之后,您可以尝试使用一些转换运算符以某种方式将其更改为所需的格式)

更新(用于简化版)

如果结果中不需要用户,而只想按userId进行过滤,则辅助类可能如下:

data class PropertiesWithFavorites(
    val displayCount:Int,val favourite:Boolean,val propertyId: Long,entityColumn = "id"
    )
    val property: Property
)

和道方法:

@Query("SELECT * FROM user_property_junction as j where j.userAccountId =:userId")
fun getPropertiesByUser(userId: Long): List<PropertiesWithFavorites>