Open In App

Android – Entity Relationship in Room

Improve
Improve
Like Article
Like
Save
Share
Report

This article describes how to define the relationship between entities in the Room persistence library. Because SQLite is a relational database, entities can be related to one another. Entities in Room cannot directly reference other entities because doing so may result in the loading of unnecessary data every time. Even so, you may want to refer to other entities from your entity at times. This can be accomplished in a variety of ways.

Objects Embedded

The @Embedded annotation can be used to represent an object that you want to decompose into subfields within a table (entity). The embedded fields can then be queried in the same way that other individual columns can.

Kotlin




data class GeeksforGeeks(
  val course: String?,
  val courseName: String?,
  val city: String?,
  val coursePrice: Int
)
 
@Entity
data class User(
  @PrimaryKey val id: Int,
  val firstName: String?,
  @Embedded val GeeksforGeeks: GeeksforGeeks?
)


GeekTip#1: If an entity has multiple embedded fields of the same type, you can use the prefix property to make each column unique. The provided value is then appended to the beginning of each column name in the embedded object.

In the preceding example, an object’s fields are decomposed into an entity. The @Embedded annotation cannot be used to represent a relationship between multiple entities. You can define the relationship between two entities using either the @Relation annotation or the foreign keys parameter of the @Entity annotation. They differ in that the @Relation annotation can only be applied to non-entity classes, whereas the ForeignKey annotation can only be applied to entity classes. ForeignKey also has an impact on the schema of an entity that requires the child column(s) to exist in the parent column (s). @Relation is used to join tables without affecting their schema.

There are three ways to define the relationship between entities:

  1. One-on-one interaction
  2. One-to-many or one-to-many relationship a one-to-many relationship
  3. Many-to-many connection

One-on-one Interactions

A one-to-one relationship exists when each instance of the parent entity corresponds to exactly one instance of the child entity, and vice versa. Consider a music streaming app in which the user has a library of their own songs. Each user has a single library, and each library corresponds to a single user.

Kotlin




@Entity
data class GfgCourseName(
  @PrimaryKey val gfgLoginNumber: Long,
  val name: String,
  val class: Int
)
 
@Entity(foreignKeys = @ForeignKey(entity = GfgCourseName.class,
    parentColumns = "gfgLoginNumber",
    childColumns = "courseActiveID",
    onDelete = CASCADE))
data class GfgCourse(
  @PrimaryKey val gfgCourseId: Long,
  val title: String,
  val courseActiveID: Long
)
data class GfgCourseNameAndGfgCourse(
  @Embedded val gfgCourseName: GfgCourseName,
  @Relation(
      parentColumn = "gfgLoginNumber",
      entityColumn = "courseActiveID"
  )
  val gfgCourse: GfgCourse
)


In the preceding example, the entities with a one-to-one relationship are gfgCourseName and coursegfg. One of the entities must include a variable that refers to the other entity’s primary key (userOwnerId in gfgCourse entity). To query the list of users and corresponding libraries, we must first model the two entities’ one-to-one relationship, which is done using the UserAndLibrary class. The CourseandGfgCourse class contains one instance of the parent entity (gfgCourseName) and one instance of the child entity (gfgCourse). 

Then, with the parent, add the @Relation annotation to the instance of the child entity. Column set to the name of the parent entity’s and entity’s primary key column  set to the name of the child entity’s column that refers to the primary key of the parent entity.

Relationships that are one-to-many

A one-to-many relationship is one in which 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 one instance of the parent entity. A course can have multiple videoPlaylists in the previous courseStructure app example. Each course can create an unlimited number of playlists, but each playlist is created by only one course.

Kotlin




@Entity
data class GfgCourseName(
  @PrimaryKey val gfgCourseNameId: Long,
  val name: String,
  val age: Int
)
 
@Entity(foreignKeys = @ForeignKey(entity = GfgCourseName.class,
    parentColumns = "gfgCourseNameId",
    childColumns = "gfgCourseNameCreatorId",
    onDelete = CASCADE))
  data class Playlist(
  @PrimaryKey val courseId: Long,
  val gfgCourseNameCreatorId: Long,
  val playlistName: String
)
 
data class GfgCourseNameWithPlaylists(
  @Embedded val gfgCourseName: GfgCourseName,
  @Relation(
      parentColumn = "gfgCourseNameId",
      entityColumn = "gfgCourseNameCreatorId"
  )
  val playlists: List<Playlist>
)


As can be seen, the approach is very similar to a one-on-one relationship; the only difference is in the relationship model (UserWithPlaylists). Instead of a single child entity, it now has a list of child entities. The process of querying the database is also very similar.

Many-to-many connections

A many-to-many relationship exists between two entities when each instance of the parent entity corresponds to zero or more instances of the child entity, and vice versa. In the case of the music streaming app, each playlist can contain many songs, and each song can be part of multiple playlists. As a result, the Playlist entity and the Song entity should have a many-to-many relationship.

Many-to-many relationships differ from other types of relationships in that there is no reference to the parent entity in the child entity. Instead, a third class is used to represent the two entities’ associative entity (or cross-reference table). The cross-reference table must include columns for the primary key from each entity in the table’s many-to-many relationship.

Kotlin




@Entity
data class CourseVideo(
  @PrimaryKey val id: Long,
  val courseVideoName: String
)
 
@Entity
data class CourseNameSignture(
  @PrimaryKey val id: Long,
  val courseNameSigntureName: String,
  val artist: String
)
 
@Entity(primaryKeys = ["courseVideoId", "courseNameSigntureId"],
    foreignKeys = {
      @ForeignKey(entity = CourseVideo.class,
      parentColumns = "id",
      childColumns = "courseVideoId"),
      @ForeignKey(entity = CourseNameSignture.class,
      parentColumns = "id",
      childColumns = "courseNameSigntureId")
}))
 
data class CourseVideoCourseNameSigntureCrossRef(
  val courseVideoId: Long,
  val courseNameSigntureId: Long
)


The next step is determined by how you want to query these related entities. Create a new data class that contains a single Playlist object and a list of all of the Song objects that the playlist includes 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 Song object and a list of all the Playlist objects in which the song is included if you want to query songs and a list of the corresponding playlists for each. 

In either case, model the relationship between the entities by identifying the cross-reference entity providing the relationship between the Playlist entity and the Song entity using the associateBy property in the @Relation annotation in each of these classes.

Kotlin




data class CourseNameSignature(
  @Embedded val videoPlaylist: VideoPlaylist,
  @Relation(
      parentColumn = "videoPlaylistId",
      entityColumn = "courseID",
      associateBy = @Junction(VideoPlaylistSongCrossRef::class)
  )
  val songs: List<Song>
)
 
data class CourseNamePlaylist(
  @Embedded val song: Song,
  @Relation(
      parentColumn = "courseID",
      entityColumn = "videoPlaylistId",
      associateBy = @Junction(VideoPlaylistSongCrossRef::class)
  )
  val videoPlaylists: List<VideoPlaylist>
)


The querying of the database is similar to the previous methods.

Kotlin




@Transaction
@Query("SELECT * FROM Playlist")
fun getPlaylistCourse(): List<PlaylistWithCourseNames>
@Transaction
@Query("SELECT * FROM CourseName")
fun getCourseNamesWithPlaylists(): List<CourseNameWithPlaylists>




Last Updated : 11 May, 2022
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads