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

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

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