تحديد العلاقات بين عناصر متعددة وطلبات البحث عنها

العلاقة بين عناصر متعددة هي علاقة ترتبط فيها كل مثيل من العنصر الرئيسي بصفر أو أكثر من المثيلات للعنصر الثانوي، وينطبق العكس أيضًا.

في مثال تطبيق بث الموسيقى، نأخذ الأغاني في قوائم التشغيل التي يحدّدها المستخدمون في الاعتبار. يمكن أن تتضمّن كل قائمة تشغيل العديد من الأغاني، ويمكن أن تكون كل أغنية جزءًا من قوائم تشغيل مختلفة. وبالتالي، هناك علاقة أطراف بأطراف بين عنصر 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();