Relationships are essential concept in projecting and implementing your database. Learn how to define and use one-to-one, one-to-many and many-to-many relationships in Android Room.

For those who want to jump into the code, check the data package inside:

One-To-One
@Entity
data class UserEntity(
@PrimaryKey val id: Long,
val name: String,
val surname: String,
)

@Entity
data class LibraryEntity(
@PrimaryKey val id: Long,
val ownerId: Long,
)

Now that we have defined the entities, how do we query them together? You must create a new class that embeds the User and uses the relation between the Library and the User.

data class UserWithLibrary(
@Embedded val user: UserEntity,
@Relation(
parentColumn = "id",
entityColumn = "ownerId",
)
val library: LibraryEntity,
)

Then, in your DAO, you can query it together:

@Transaction
@Query("SELECT * FROM UserEntity")
suspend fun getUsersWithLibraries(): List<UserWithLibrary>

Querying a class with Relation fields requires you to use @Transaction.

One-To-Many

Now, let’s add the Collections so the Users can create them inside their Library.

@Entity
data class CollectionEntity(
@PrimaryKey val id: Long,
val name: String,
val libraryId: Long,
)

Similar to a one-to-one relationship, we need to create a class with an @Relation, but its field will be a list.

data class LibraryWithCollections(
@Embedded val library: LibraryEntity,
@Relation(
parentColumn = "id",
entityColumn = "libraryId"
)
val collections: List<CollectionEntity>,
)

Then, in your DAO, query it together with libraries:

@Transaction
@Query("SELECT * FROM LibraryEntity")
suspend fun getLibrariesWithCollections(): List<LibraryWithCollections>

Now, we want to allow Users to add Games to their Collections and let other Users browse Collections containing the Game to find new exciting games. To make many-to-many relationships possible, we need a cross-reference table.

@Entity
data class GameEntity(
@PrimaryKey val id: Long,
val name: String,
)

@Entity
data class CollectionGameCrossRef(
@PrimaryKey val collectionId: Long,
@PrimaryKey val gameId: Long,
)

Now, there’ll be two classes using the relation:

data class GameWithCollections(
@Embedded val game: GameEntity,
@Relation(
parentColumn = "id",
entityColumn = "id",
associateBy = Junction(CollectionGameCrossRef::class)
)
val collection: List<CollectionEntity>,
)

data class CollectionWithGames(
@Embedded val collection: CollectionEntity,
@Relation(
parentColumn = "id",
entityColumn = "id",
associateBy = Junction(CollectionGameCrossRef::class)
)
val games: List<GameEntity>,
)

They’re very similar because we named the primary key inside GameEntity and CollectionEntity with the same name id. Then you’re able to query it inside your DAO:

@Transaction
@Query("SELECT * FROM CollectionEntity")
fun getCollectionsWithGames(): List<CollectionWithGames>

@Transaction
@Query("SELECT * FROM GameEntity")
fun getGamesWithCollections(): List<GameWithCollections>

Congratulations! Now you know how to define and use all possible relationships between data in Room! I’ll be grateful for a 👏 if you like it!

Check out the GitHub code:

References:

Source link