تعریف و پُرسمان روابط تودرتو

گاهی اوقات، ممکن است نیاز داشته باشید مجموعه‌ای از سه یا چند جدول را که همه با یکدیگر مرتبط هستند پُرسمان کنید. در این حالت، روابط تودرتو بین جدول‌ها تعریف می‌کنید.

فرض کنید در مثال برنامه جاری‌سازی موسیقی، می‌خواهید همه کاربران، همه فهرست‌های پخش برای هر کاربر، و همه آهنگ‌های موجود در هر فهرست پخش برای هر کاربر را پُرسمان کنید. کاربران با فهرست‌های پخش رابطه یک به چند دارند و فهرست‌های پخش با آهنگ‌ها رابطه چند به چند دارند. مثال کد زیر کلاس‌هایی را نشان می‌دهد که این نهادها را نشان می‌دهند و همچنین جدول ارجاع متقابل برای رابطه چند به چند بین فهرست‌های پخش و آهنگ‌ها:

@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>
)

کلاس UserWithPlaylistsAndSongs به‌طور غیرمستقیم روابط بین هر سه کلاس نهاد را مدل‌سازی می‌کند: User، Playlist، و Song. این موضوع در شکل ۱ نشان داده شده است.

‫UserWithPlaylistsAndSongs رابطه بین «کاربر» و
  «فهرست پخش با آهنگ‌ها» را مدل می‌کند، که به نوبه خود رابطه بین «فهرست پخش»
  و «آهنگ» را مدل می‌کند.
شکل ۱. نمودار کلاس‌های رابطه در برنامه جاری‌سازی موسیقی نمونه.

اگر مجموعه شما جدول‌های بیشتری دارد، کلاسی برای مدل‌سازی رابطه بین هر جدول باقی‌مانده و کلاس رابطه قبلی ایجاد کنید. این فرایند زنجیره‌ای از روابط تودرتو بین همه جدول‌هایی که می‌خواهید پُرسمان کنید ایجاد می‌کند.

درنهایت، تابعی به کلاس شیء دسترسی به داده (DAO) اضافه کنید تا تابع پُرسمان موردنیاز برنامه‌تان را آشکار کند. این تابع برای اجرای چندین پُرسمان به Room نیاز دارد، بنابراین حاشیه نویسی @Transaction را اضافه کنید تا کل عملکرد به‌صورت اتمی اجرا شود:

@Transaction
@Query("SELECT * FROM User")
suspend fun getUsersWithPlaylistsAndSongs(): List<UserWithPlaylistsAndSongs>