הגדרה של קשרי גומלין 'הרבה לרבים' ושליחת שאילתות לגבי קשרים כאלה

קשר גומלין מסוג רבים לרבים בין שתי ישויות הוא קשר שבו כל מופע של ישות אם מתאים לאפס או יותר מופעים של ישות הצאצא, וגם ההפך נכון.

בדוגמה של אפליקציית סטרימינג של מוזיקה, צריך להתייחס לשירים בפלייליסטים שהוגדרו על ידי המשתמש. כל פלייליסט יכול לכלול הרבה שירים, וכל שיר יכול להיות חלק מהרבה פלייליסטים שונים. לכן, יש קשר רבים לרבים בין הישות Playlist לישות Song.

כדי להגדיר ולשאול על קשרים מסוג רבים לרבים במסד הנתונים:

  1. הגדרת קשר הגומלין: מגדירים את הישויות ואת הישות המשויכת (טבלת הצלבת נתונים) כדי לייצג את קשר הגומלין מסוג רבים לרבים.
  2. שליחת שאילתות לישויות: קובעים איך רוצים לשלוח שאילתות לישויות הקשורות ויוצרים מחלקות נתונים שמייצגות את הפלט הרצוי.

הגדרת הקשר

כדי להגדיר קשר רבים לרבים, קודם יוצרים מחלקה לכל אחת משתי הישויות. קשרים מסוג רבים לרבים שונים מסוגים אחרים של קשרים כי בדרך כלל אין הפניה לישות אם בישות הבן. במקום זאת, יוצרים מחלקה שלישית שמייצגת ישות אסוציאטיבית או טבלת הפניות צולבות בין שתי הישויות. בטבלת ההצלבה צריכות להיות עמודות למפתח הראשי מכל ישות בקשר רבים-לרבים שמיוצג בטבלה. בדוגמה הזו, כל שורה בטבלת ההצלבה מתאימה לזיווג של מופע Playlist ומופע Song שבו השיר שאליו מתבצעת ההפניה כלול בפלייליסט שאליו מתבצעת ההפניה.

Kotlin

@Entity
data class Playlist(
    @PrimaryKey val playlistId: Long,
    val playlistName: String
)

@Entity
data class Song(
    @PrimaryKey val songId: Long,
    val songName: String,
    val artist: String
)

@Entity(primaryKeys = ["playlistId", "songId"])
data class PlaylistSongCrossRef(
    val playlistId: Long,
    val songId: Long
)

Java

@Entity
public class Playlist {
    @PrimaryKey public long playlistId;
    public String playlistName;
}

@Entity
public class Song {
    @PrimaryKey public long songId;
    public String songName;
    public String artist;
}

@Entity(primaryKeys = {"playlistId", "songId"})
public class PlaylistSongCrossRef {
    public long playlistId;
    public long songId;
}

שליחת שאילתה לגבי הישויות

השלב הבא תלוי באופן שבו רוצים לשאול שאילתות לגבי הישויות הקשורות האלה.

  • אם רוצים לשלוח שאילתה לגבי פלייליסטים ולקבל רשימה של שירים תואמים לכל פלייליסט, צריך ליצור מחלקת נתונים חדשה שמכילה אובייקט Playlist אחד ורשימה של כל האובייקטים Song שהפלייליסט כולל.
  • אם רוצים לשלוח שאילתה לגבי שירים ולקבל רשימה של פלייליסטים תואמים לכל שיר, צריך ליצור מחלקת נתונים חדשה שמכילה אובייקט Song יחיד ורשימה של כל האובייקטים מסוג Playlist שבהם השיר נכלל.

בכל מקרה, כדי להגדיר את הקשר בין הישויות, צריך להשתמש במאפיין associateBy בהערת @Relation בכל אחת מהמחלקות האלה כדי לזהות את ישות ההפניה הצולבת שמספקת את הקשר בין ישות Playlist לישות Song.

Kotlin

data class PlaylistWithSongs(
    @Embedded val playlist: Playlist,
    @Relation(
         parentColumn = "playlistId",
         entityColumn = "songId",
         associateBy = Junction(PlaylistSongCrossRef::class)
    )
    val songs: List<Song>
)

data class SongWithPlaylists(
    @Embedded val song: Song,
    @Relation(
         parentColumn = "songId",
         entityColumn = "playlistId",
         associateBy = Junction(PlaylistSongCrossRef::class)
    )
    val playlists: List<Playlist>
)

Java

public class PlaylistWithSongs {
    @Embedded public Playlist playlist;
    @Relation(
         parentColumn = "playlistId",
         entityColumn = "songId",
         associateBy = @Junction(PlaylistSongCrossref.class)
    )
    public List<Song> songs;
}

public class SongWithPlaylists {
    @Embedded public Song song;
    @Relation(
         parentColumn = "songId",
         entityColumn = "playlistId",
         associateBy = @Junction(PlaylistSongCrossref.class)
    )
    public List<Playlist> playlists;
}

לבסוף, מוסיפים שיטה למחלקת ה-DAO כדי לחשוף את פונקציית השאילתה שהאפליקציה צריכה.

  • getPlaylistsWithSongs: השיטה הזו שולחת שאילתה למסד הנתונים ומחזירה את כל האובייקטים של PlaylistWithSongs שמתקבלים.
  • getSongsWithPlaylists: השיטה הזו שולחת שאילתה למסד הנתונים ומחזירה את כל האובייקטים של SongWithPlaylists שמתקבלים.

כל אחת מהשיטות האלה דורשת מ-Room להריץ שתי שאילתות, ולכן צריך להוסיף את ההערה @Transaction לשתי השיטות כדי שהפעולה כולה תתבצע באופן אטומי.

Kotlin

@Transaction
@Query("SELECT * FROM Playlist")
fun getPlaylistsWithSongs(): List<PlaylistWithSongs>

@Transaction
@Query("SELECT * FROM Song")
fun getSongsWithPlaylists(): List<SongWithPlaylists>

Java

@Transaction
@Query("SELECT * FROM Playlist")
public List<PlaylistWithSongs> getPlaylistsWithSongs();

@Transaction
@Query("SELECT * FROM Song")
public List<SongWithPlaylists> getSongsWithPlaylists();