Home > OS >  Room @Relation annotation with a One To Many relationship
Room @Relation annotation with a One To Many relationship

Time:06-23

I have a POJO I'd like to get from the database which has a list of POJO's as a property. This, according to docs is doable via a @Relationship annotation. However, it's a one to many relationship where I don't directly reference the table/entity in question. How would I go about getting this back from the DB directly from the DAO? Is this even possible, or do I have to implement some intermediary binding logic manually? The POJO I'd like to get from DB:

data class Chore(
    var name: String,
    //This is the line that doesn't work
    @Relation(parentColumn = "id", entityColumn = "userId", entity = UserEntity::class)
    var contributingUsers: List<User>,
    @DrawableRes var drawableRes: Int,
    var done: Boolean
)

The User POJO I'd like to get automatically mapped:

data class User(
    val userName: String,
    @DrawableRes val userPhoto: Int
)

The One-To-Many reference table/entity:

@Entity(
    tableName = TableNames.CHORE_TO_USER,
    foreignKeys = [
        ForeignKey(
            entity = UserEntity::class,
            parentColumns = arrayOf("id"),
            childColumns = arrayOf("userId"),
            onDelete = ForeignKey.CASCADE,
            onUpdate = ForeignKey.CASCADE,
        ),
        ForeignKey(
            entity = ChoreEntity::class,
            parentColumns = arrayOf("id"),
            childColumns = arrayOf("choreId"),
            onDelete = ForeignKey.CASCADE,
            onUpdate = ForeignKey.CASCADE,
        )
    ],
    indices = [Index("choreId"), Index("userId")]
)
internal data class ChoreToUser(
    val userId: Int,
    val choreId: Int,
    val canFulfill: Boolean,
): BaseEntity()

The query:

    @Query("SELECT Chores.name, drawableRes,"  
            "Users.name as userName, Users.imageRes as userPhoto, "  
            "(COUNT(ChoreLogs.id) = 1) as done "  
            "FROM Chores "  
            "LEFT JOIN ChoreToUsers ON ChoreToUsers.choreId = Chores.id "  
            "LEFT JOIN Users ON ChoreToUsers.userId = Users.id "  
            "LEFT JOIN ChoreLogs ON ChoreLogs.choreToUserId = ChoreToUsers.id")
    fun getChoreTiles(): List<Chore>

TLDR: I wanna embed a list of users into the Chore POJO. It's refferenced via an intermediary table. How would I go about doing this?

CodePudding user response:

To use @Relation the parent table must be available so that the parent column can be found.

So you would need something along the lines of :-

data class Chore(
    @Embedded
    var choreEntity: ChoreEntity, //<<<<<
    var name: String,
    //This is the line that doesn't work
    @Relation(parentColumn = "id", entityColumn = "userId", entity = UserEntity::class)
    var contributingUsers: List<User>,
    @DrawableRes var drawableRes: Int,
    var done: Boolean
)

In short @Relation results in a sub query being invoked that retrieves ALL of the children of the parent (which MUST exist/be known) thus an @Embed of that parent is required. Note that these are for use by the convenience methods, which are a little restrictive in nature.

However, as you have an intermediate table (mapping/associative/reference .... table) then you need to tell Room about this by using the associateBy parameter to define the enter image description here

enter image description here

and

enter image description here

  • Note that above data takes advantage of the many-many allowable by an associative table.

Results (aka output included in the log, split per example)

DBINFO_EX01: Chore is Chore1   User is User1
DBINFO_EX01: Chore is Chore1   User is user3
DBINFO_EX01: Chore is Chore2   User is User1
DBINFO_EX01: Chore is Chore2   User is user3
DBINFO_EX01: Chore is Chore3   User is User1
DBINFO_EX01: Chore is Chore3   User is user3
DBINFO_EX01: Chore is Chore4   User is User1
DBINFO_EX01: Chore is Chore4   User is user3
DBINFO_EX01: Chore is Chore5   User is User2
DBINFO_EX01: Chore is Chore5   User is user3
DBINFO_EX01: Chore is Chore6   User is User2
DBINFO_EX01: Chore is Chore6   User is user3


DBINFOEX02: Chore is Chore1, image is 10000, there are 2  contributing Users:-
DBINFOEX02:     User is User1, photo is 1000
DBINFOEX02:     User is user3, photo is 3000
DBINFOEX02: Chore is Chore2, image is 20000, there are 2  contributing Users:-
DBINFOEX02:     User is User1, photo is 1000
DBINFOEX02:     User is user3, photo is 3000
DBINFOEX02: Chore is Chore3, image is 30000, there are 2  contributing Users:-
DBINFOEX02:     User is User1, photo is 1000
DBINFOEX02:     User is user3, photo is 3000
DBINFOEX02: Chore is Chore4, image is 40000, there are 2  contributing Users:-
DBINFOEX02:     User is User1, photo is 1000
DBINFOEX02:     User is user3, photo is 3000
DBINFOEX02: Chore is Chore5, image is 50000, there are 2  contributing Users:-
DBINFOEX02:     User is User2, photo is 2000
DBINFOEX02:     User is user3, photo is 3000
DBINFOEX02: Chore is Chore6, image is 60000, there are 2  contributing Users:-
DBINFOEX02:     User is User2, photo is 2000
DBINFOEX02:     User is user3, photo is 3000


DBINFOEX03: Chore is Chore1, image is 10000, there are 2 contributing users:-
DBINFOEX03:     User is User1, photo is 1000
DBINFOEX03:     User is user3, photo is 3000
DBINFOEX03: Chore is Chore2, image is 20000, there are 2 contributing users:-
DBINFOEX03:     User is User1, photo is 1000
DBINFOEX03:     User is user3, photo is 3000
DBINFOEX03: Chore is Chore3, image is 30000, there are 2 contributing users:-
DBINFOEX03:     User is User1, photo is 1000
DBINFOEX03:     User is user3, photo is 3000
DBINFOEX03: Chore is Chore4, image is 40000, there are 2 contributing users:-
DBINFOEX03:     User is User1, photo is 1000
DBINFOEX03:     User is user3, photo is 3000
DBINFOEX03: Chore is Chore5, image is 50000, there are 2 contributing users:-
DBINFOEX03:     User is User2, photo is 2000
DBINFOEX03:     User is user3, photo is 3000
DBINFOEX03: Chore is Chore6, image is 60000, there are 2 contributing users:-
DBINFOEX03:     User is User2, photo is 2000
DBINFOEX03:     User is user3, photo is 3000
  • as can be seen EX02 and EX03 produce the same output.
  • Related