Android Room Many to Many Junction table 获得超过 2 tables 的关系

Android Room Many to Many Junction table getting more than relation of 2 tables

我已经在用户属性 和这两个项目的连接点table 之间创建了关系用户属性连接点可以在下图中可视化为关系

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
}

和交汇点 table 而不是 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
)

并与

建立关系class
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>
)

还需要获取这些属性被用户展示和点赞的次数数据。

为此检查了解决方案 ,它为连接添加了额外的字段,在我的例子中添加了 displayCountfavorite 属性

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

我的第一个问题是,据我所知,没有多少结点或关联 tables 的经验,它们只存储应该关联的 tables 的外键,是吗可以将值字段添加到联结 table?

如果这样做不优雅或不是首选方式,我是否应该添加另一个与连接点 table 相关的 table,例如

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

并将它们关联起来?

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

data class UserWithProperties(

    @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>
)

并根据您对第一个问题的回答,从状态 table 或交叉点 table 获得 SELECT 或者是否可以使用 @Embedded@Relation

添加另一个与 UserWithProperties 的关系

据我所知,不幸的是,没有 out-of-the-box 方法可以仅使用 Room 的工具(@Relation、@Embedded、@Junction)解决您的用例。

My first question is as far as i have seen, not much experience with junction or associative tables, they only store foreign keys for the tables that should associate with, is it okay to add value fields to junction table?

问题是 @Junction 在使用上有一些限制——它只是帮助绑定两个 tables 与第三个(连接点)table 中保留的值。但是 @Relation-with-@Junction API 不支持从这个连接点 table 获取任何要包含到结果 class 的字段(这些外键仅用于绑定)。这就是为什么从技术上讲,您可以向联结点 table 添加一些字段(这似乎是您应该保留这些值的最合适 table 的地方),但实际上您无法使用这些字段@Junction.

也许您可以使用一些 hack-ish 方法,但我的猜测 - 您必须使用 SQL 连接实现自己的方法,并通过循环传递结果以形成所需的结果(与您在 post 中提到的 link 中实施的类似)。

作为对你的情况的简化,你真的可以按照你的建议描述Entity-junction table(但根本不使用@Junction):

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

然后添加辅助class(非实体)作为查询结果:

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,
)

当然,这不是你想要的,但至少你可以处理它,它是 out-of-the-box 并且你可以使用 LiveData/Flow/RxJava (例如,在得到这个之后你可以尝试使用一些转换运算符以某种方式将其更改为所需格式)

更新(简化版)

如果您不需要结果中的用户,而只是想通过 userId 进行过滤,那么您的辅助 class 可以如下所示:

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

和dao方法:

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