לפעמים, יכול להיות שתצטרכו להריץ שאילתה על קבוצה של שלוש טבלאות או יותר שכולן קשורות זו לזו. במקרה כזה, מגדירים קשרי גומלין מקוננים בין הטבלאות.
נניח שבדוגמה של אפליקציית סטרימינג של מוזיקה, רוצים לשלוח שאילתה לגבי כל המשתמשים, כל הפלייליסטים של כל משתמש וכל השירים בכל פלייליסט של כל משתמש. למשתמשים יש קשר של אחד לרבים עם פלייליסטים, ולפלייליסטים יש קשר של רבים לרבים עם שירים. בדוגמת הקוד הבאה מוצגות המחלקות שמייצגות את הישויות האלה, וגם טבלת ההפניות הצולבות לקשר של רבים לרבים בין פלייליסטים לשירים:
@Entity data class User( @PrimaryKey val userId: Long, val name: String, val age: Int ) @Entity data class Playlist( @PrimaryKey val playlistId: Long, val userCreatorId: Long, val playlistName: String ) @Entity data class Song( @PrimaryKey val songId: Long, val songName: String, val artist: String ) @Entity(primaryKeys = ["playlistId", "songId"], indices = [Index("playlistId", "songId")]) data class PlaylistSongCrossRef( val playlistId: Long, val songId: Long )
קודם כול, יוצרים מודל של הקשר בין שתיים מהטבלאות בסט, כמו שעושים בדרך כלל, באמצעות מחלקת נתונים וההערה @Relation. בדוגמה הבאה מוצג מחלקה PlaylistWithSongs שמייצגת קשר רבים לרבים בין מחלקת הישות Playlist למחלקת הישות Song:
data class PlaylistWithSongs( @Embedded val playlist: Playlist, @Relation( parentColumns = ["playlistId"], entityColumns = ["songId"], associateBy = Junction(PlaylistSongCrossRef::class) ) val songs: List<Song> )
אחרי שמגדירים מחלקה של נתונים שמייצגת את הקשר הזה, יוצרים עוד מחלקה של נתונים שמדמה את הקשר בין טבלה אחרת מהקבוצה לבין מחלקת הקשר הראשונה, כך שהקשר הקיים מוטמע בקשר החדש. בדוגמה הבאה מוצגת מחלקה UserWithPlaylistsAndSongs שמדמה קשר של אחד לרבים בין מחלקת הישות User לבין מחלקת הקשר PlaylistWithSongs:
data class UserWithPlaylistsAndSongs( @Embedded val user: User, @Relation( entity = Playlist::class, parentColumns = ["userId"], entityColumns = ["userCreatorId"] ) val playlists: List<PlaylistWithSongs> )
הקשרים בין שלושת סוגי הישויות: User, Playlist ו-Song מיוצגים באופן עקיף על ידי המחלקה UserWithPlaylistsAndSongs. האיור 1 ממחיש את זה.
אם יש לכם עוד טבלאות, צריך ליצור מחלקה כדי למדל את הקשר בין כל טבלה שנותרה לבין מחלקת הקשר הקודמת. התהליך הזה יוצר שרשרת של קשרים מוכללים בין כל הטבלאות שרוצים להריץ עליהן שאילתה.
לבסוף, מוסיפים פונקציה למחלקה של אובייקט הגישה לנתונים (DAO) כדי לחשוף את פונקציית השאילתה שהאפליקציה צריכה. הפונקציה הזו דורשת מ-Room להריץ כמה שאילתות, לכן צריך להוסיף את ההערה @Transaction כדי שהפעולה כולה תרוץ באופן אטומי:
@Transaction @Query("SELECT * FROM User") suspend fun getUsersWithPlaylistsAndSongs(): List<UserWithPlaylistsAndSongs>