Note: This article is part of the advanced Room series which covers all the details about the Room persistence library. You can read all the articles here:
- Introduction to Room Persistent Library in Android
- Data Access Objects — DAO in Room
- Entity Relationship in Room [You are here]
- How does Room work internally?
- Room Database Migrations
- Using Room with LiveData and other third-party libraries
Entity Relationships in Room
This article covers how we can define relationship between entities in Room persistence library.
Since SQLite is a relational database, entities can have relationships between them. In Room, entities cannot directly reference other entities because it might cause loading unnecessary data every time.
Still sometimes, you would want to reference other entities from your entity. You can acheive this in multiple ways.
Embedded Objects
You can use the @Embedded
annotation to represent an object that you'd like to decompose into its subfields within a table(entity). You can then query the embedded fields just as you would for other individual columns.
Embedded fields can also include other embedded fields.
The table representing a User
object then contains columns with the following names: id
, firstName
, street
, state
, city
, and postCode
.
If an entity has multiple embedded fields of the same type, you can keep each column unique by setting the
prefix
property. Room then adds the provided value to the beginning of each column name in the embedded object.
In the above example, fields of an object are decomposed into an entity. In case you want to represent relationship between multiple entities, you cannot use the @Embedded
annotation.
You can use either @Relation
annotation or foreignkeys
parameter of @Entity annotation for defining relationship between two entities.
Both of them are different from each other in such a way that @Relation
annotation can only be applied on a non-entity class whereas ForeignKey
is used on an entity class. Also, ForeignKey
affects the schema of an entity that requires that the child column(s) exist in the parent column(s). @Relation
is used to join the tables without affecting the schema of tables.
You can define relationship between entities in 3 ways:
- One-to-one relationship
- One-to-many relationship or Many-to-one relationship
- Many-to-many relationship
One-to-one relationships
A one-to-one relationship between two entities is a relationship where each instance of the parent entity corresponds to exactly one instance of the child entity, and vice-versa.
For example, consider a music streaming app where the user has a library of songs that they own. Each user has only one library, and each library corresponds to exactly one user.
In the above example, User
and Library
are the entities which have one-to-one relationship. One of the entities must include a variable that is a reference to the primary key of the other entity(userOwnerId
in Library
entity).
In order to query the list of users and corresponding libraries, we must first model the one-to-one relationship between the two entities, which is done using UserAndLibrary
class. The UserAndLibrary
class contains an instance of the parent entity(User
) and the corresponding instance of the child entity(Library
). Then, add the @Relation
annotation to the instance of the child entity, with parentColumn
set to the name of the primary key column of the parent entity and entityColumn
set to the name of the column of the child entity that references the parent entity's primary key.
Now we can query our database in the following way:
This method requires Room to run two queries, so add the
@Transaction
annotation to this method to ensure that the whole operation is performed atomically.
One-to-many relationships
A one-to-many relationship between two entities is a relationship where each instance of the parent entity corresponds to zero or more instances of the child entity, but each instance of the child entity can only correspond to exactly one instance of the parent entity.
In the previous music streaming app example, a User
can have multiple playlists. Each user can create as many playlists as they want, but each playlist is created by exactly one user.
As we can see, the approach is very similar to one-to-one relationship, the only difference here is in the relationship model(UserWithPlaylists
). Instead of containing a single child entity, it now contains a list of child entity. Querying the database is also very similar.
Many-to-many relationships
A many-to-many relationship between two entities is a relationship where each instance of the parent entity corresponds to zero or more instances of the child entity, and vice-versa.
In the music streaming app example, each playlist can include many songs, and each song can be a part of many different playlists. Therefore, there should be a many-to-many relationship between the Playlist
entity and the Song
entity.
Many-to-many relationships are distinct from other relationship types because there is generally no reference to the parent entity in the child entity. Instead, a third class is used to represent an associative entity (or cross-reference table) between the two entities. The cross-reference table must have columns for the primary key from each entity in the many-to-many relationship represented in the table.
Now, the next step depends on how you want to query these related entities.
- If you want to query playlists and a list of the corresponding songs for each playlist, create a new data class that contains a single
Playlist
object and a list of all of theSong
objects that the playlist includes. - If you want to query songs and a list of the corresponding playlists for each, create a new data class that contains a single
Song
object and a list of all of thePlaylist
objects in which the song is included.
In either case, model the relationship between the entities by using the associateBy
property in the @Relation
annotation in each of these classes to identify the cross-reference entity providing the relationship between the Playlist
entity and the Song
entity.
Querying the database is similar to the previous approaches.
That’s all about the entity relationships in Room. Thank You!!!