Çoklu-çoklu ilişkileri tanımlama ve sorgulama

İki varlık arasındaki çoktan çok ilişki, ana varlığın her örneğinin alt varlığın sıfır veya daha fazla örneğine karşılık geldiği ve bunun tersinin de geçerli olduğu bir ilişkidir.

Müzik akışı uygulaması örneğinde, kullanıcı tanımlı oynatma listelerindeki şarkıları ele alalım. Her oynatma listesi birçok şarkı içerebilir ve her şarkı birçok oynatma listesinde yer alabilir. Bu nedenle, Playlist ve Song varlıkları arasında çoka-çok ilişki vardır.

Veritabanınızdaki çoktan çokaya ilişkileri tanımlamak ve sorgulamak için aşağıdaki adımları uygulayın:

  1. İlişkiyi tanımlayın: Çoka çok ilişkiyi temsil etmek için varlıkları ve ilişkili varlığı ya da çapraz referans tablosunu oluşturun.
  2. Varlıkları sorgulama: İlgili varlıkları nasıl sorgulamak istediğinizi belirleyin ve amaçlanan çıkışı temsil edecek veri sınıfları oluşturun.

İlişkiyi tanımlama

Çoktan çoğa ilişki tanımlamak için öncelikle iki varlığınızın her biri için bir sınıf oluşturun. Çoktan çoka ilişkiler, genellikle alt öğede üst öğeye referans verilmediği için diğer ilişki türlerinden farklıdır. Bunun yerine, iki öğe arasında ilişkilendirilmiş bir öğeyi veya çapraz referans tablosunu temsil eden üçüncü bir sınıf oluşturun. Çapraz başvuru tablosunda, tabloda gösterilen çoktan çoğa ilişkideki her öğenin birincil anahtarı için sütunlar olmalıdır. Bu örnekte, çapraz referans tablosundaki her satır, referans verilen şarkının referans verilen oynatma listesinde yer aldığı bir Playlist örneği ile bir Song örneğinin eşleşmesine karşılık gelir.

@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"], indices = [Index("playlistId", "songId")])
data class PlaylistSongCrossRef(
    val playlistId: Long,
    val songId: Long
)

Varlıkları sorgulama

Bir sonraki adım, bu ilgili öğeleri nasıl sorgulamak istediğinize bağlıdır.

  • Oynatma listelerini ve her oynatma listesi için ilgili şarkıların listesini sorgulamak istiyorsanız tek bir Playlist nesnesi ve oynatma listesinin içerdiği Song nesnelerinin listesini içeren yeni bir veri sınıfı oluşturun.
  • Şarkıları ve her şarkı için ilgili oynatma listelerinin listesini sorgulamak istiyorsanız tek bir Song nesnesi ve şarkıyı içeren Playlist nesnelerinin listesini içeren yeni bir veri sınıfı oluşturun.

Her iki durumda da, Playlist öğesi ile Song öğesi arasındaki ilişkiyi sağlayan çapraz referans öğesini tanımlamak için bu sınıfların her birindeki @Relation açıklamasında associateBy özelliğini kullanarak öğeler arasındaki ilişkiyi modelleyin.

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

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

Son olarak, uygulamanızın ihtiyaç duyduğu sorgu işlevini kullanıma sunmak için veri erişim nesnesi (DAO) sınıfına bir işlev ekleyin.

getPlaylistsWithSongs
Veritabanına sorgu gönderir ve sonuçtaki tüm PlaylistWithSongs nesneleri döndürür.
getSongsWithPlaylists
Veritabanına sorgu gönderir ve sonuçtaki tüm SongWithPlaylists nesneleri döndürür.

Her işlevin iki sorgu çalıştırması için Oda gerekir. İşlemin atomik olarak çalışmasını sağlamak için her iki işleve de @Transaction ek açıklamasını ekleyin.

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

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

Bileşik anahtarlar

İlişkiyi bileşik anahtarlar kullanarak tanımlarsanız @Relation açıklamasının parentColumns ve entityColumns bölümlerinde birden fazla sütun belirtin.

Junction içinde sütun belirtmeniz gerekiyorsa Junction açıklamasında parentColumns ve entityColumns öğelerini de kullanın.

Aşağıdaki örnekte, Playlist, playlistId ve creatorId'dan oluşan birleşik bir birincil anahtara sahiptir. Çapraz referans tablosu PlaylistSongCrossRef, oynatma listesine referans vermek için şu sütunları da içerir.

@Entity(primaryKeys = ["playlistId", "creatorId"])
data class Playlist(
    val playlistId: Long,
    val creatorId: Long,
    val playlistName: String
)

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

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

data class PlaylistWithSongs(
    @Embedded val playlist: Playlist,
    @Relation(
        parentColumns = ["playlistId", "creatorId"],
        entityColumns = ["songId"],
        associateBy = Junction(PlaylistSongCrossRef::class)
    )
    val songs: List<Song>
)