Paging Library: How to merge a result set of 3 Room Entities?

Viewed 530

It's very straightforward to use Android Paging library with Room if the list item can be directly derived from a Room Entity as described in this. But how should we go about implementing Paging if the list item is actually a composition of, let's say, 3 entities?

Consider,

data class ListItem(val name, val officeAddress, val lastTravelledPlaceName)

and

@Entity
data class User(@PrimaryKey val id, val name)


@Entity
data class Office(@PrimaryKey val id, val address)

@Entity 
data class Places(@PrimaryKey val id, val name)

One solution could be to use paging on User and then query for Office and Places during the adapter's onBind..() call, but it does not seem like the right approach.

1 Answers

@Embedded annotation can be used to combine Entities in a class.

For example using the Entities from the question then an alternative for the ListItem class could be :-

class UserOfficePlacesCombined() {

    @Embedded(prefix = "user")
    var user: User? = null
    @Embedded(prefix = "office")
    var office: Office? = null
    @Embedded(prefix = "places")
    var places: Places? = null
}
  • prefix has been used to avoid column name ambiguities, in short all columns will be prefixed with the respective table's name (see the Dao query that follows)

You could then extract a UserOfficePlacesCombined using a Dao Query such as :-

@Query("SELECT user.id AS userid, user.name AS username, " +
        "office.id AS officeid, office.address AS officeaddress, " +
        "places.id AS placesid, places.name AS placesname " +
        "FROM User JOIN Office ON User.id = Office.id JOIN Places ON User.id = Places.id")
fun getAllUserOfficePlacesCombined(): UserOfficePlacesCombined
  • Note to circumvent ambiguities all columns have been renamed using the AS keyword
  • The is no indication if the question of a relationship between the tables, as such the query will join the tables according to their id column.
    • it is unlikely that this would be of any use in an App, but has been done due the the lack of information and for convenience.

Putting this together as an example, making some assumptions then consider the following demo :-

    val userOfficePlacesDoa = db.userOfficePlacesDao()
    val user1 = User(1,"USER1")
    val office1 = Office(1,"Office1")
    val places1 = Places(1,"Place1")

    userOfficePlacesDoa.insertUser(user1)
    userOfficePlacesDoa.insertOffice(office1)
    userOfficePlacesDoa.insertPlaces(places1)
    var uopc: UserOfficePlacesCombined = userOfficePlacesDoa.getAllUserOfficePlacesCombined()
    Log.d("UOPCINFO","User Name is " + uopc.user?.name + " Office Address is" + uopc.office?.address + " Places name is " + uopc.places?.name)

The result being :-

2019-10-16 22:35:16.442 D/UOPCINFO: User Name is USER1 Office Address isOffice1 Places name is Place1
Related