Model a Room one-to-many Playlist-to-Song relationship

Tests Room relational modeling. Strong answer: Song foreign key, `@Embedded` Playlist with `@Relation` to `List<Song>`, DAO wrapped in `@Transaction`. Red flag: embedding songs in Playlist or skipping `@Transaction`, which causes N+1 queries.
WHAT THIS TESTS: This tests whether you understand how Room abstracts SQL relationships into object graphs without breaking relational normalization. The interviewer cares that you know the difference between an entity and a POJO used for projection, that you understand foreign keys for referential integrity, and that you know Room can automatically fetch related objects in a single transaction rather than forcing you to write manual joins.
A GOOD ANSWER COVERS: A good answer hits four things in order. First, define two separate entities: Playlist with a primary key, and Song with its own primary key plus a foreign key column referencing playlistId. Second, create a dedicated data class that is not an entity, such as PlaylistWithSongs, annotated with @Embedded for the Playlist field and @Relation on the List<Song> field mapping parentColumn to the Playlist primary key and entityColumn to the Song foreign key. Third, in the DAO, write a method that returns PlaylistWithSongs and annotate it with @Transaction so Room runs two queries in a single transaction and assembles the object graph for you without an N plus one problem. Fourth, mention adding an index on the Song foreign key column to avoid full table scans during the relation query.
COMMON WRONG ANSWERS: The biggest red flag is suggesting you store a list of Song objects directly inside the Playlist entity using @Embedded or a type converter, which collapses the relationship into one table and violates first normal form. Another red flag is proposing manual nested queries where you fetch all playlists then loop to query songs individually, which creates an N plus one performance disaster. A subtler mistake is forgetting @Transaction, which can leave you with partial data if the database changes between the two internal queries Room runs.
LIKELY FOLLOW-UPS: The interviewer might ask how you would model a many-to-many relationship between playlists and songs, which requires a join entity. They might ask what happens if you omit the index on the foreign key, which leads to slower relation lookups on large datasets. They could also ask how you would observe changes, prompting you to return Flow<List<PlaylistWithSongs>> so Room automatically emits updates.
ONE CONCRETE EXAMPLE: Imagine a playlist table with columns id and name, and a song table with columns songId, title, and playlistId. You define PlaylistWithSongs with @Embedded val playlist: Playlist and @Relation parentColumn set to id and entityColumn set to playlistId on val songs: List<Song>. Your DAO has @Transaction @Query SELECT * FROM playlist WHERE id = :playlistId fun getPlaylistWithSongs(playlistId: Long): PlaylistWithSongs. Room executes a select on playlist, then a select on song where playlistId matches, and maps both into the result object in one shot.
Source: developer.android.com
Read the original → developer.android.com
- #android
- #room
- #database
- #kotlin
- #sql
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.