انتخاب نوع رابطه بین اشیا

ازآنجایی‌که SQLite پایگاه داده رابطه‌ای است، می‌توانید بین نهادها رابطه تعریف کنید. اما درحالی‌که بیشتر کتابخانه‌های نگاشت شیء-ارتباطی به اشیای نهاد اجازه می‌دهند به یکدیگر ارجاع دهند، Room این کار را صریحاً ممنوع کرده است. برای آشنایی با دلیل فنی این تصمیم، به درک اینکه چرا Room اجازه نمی‌دهد از مرجع‌های شیء استفاده کنید مراجعه کنید.

انواع روابط

‫Room از انواع رابطه زیر پشتیبانی می‌کند:

  • یک‌به‌یک: نشان‌دهنده رابطه‌ای است که در آن یک نهاد واحد با نهاد واحد دیگری مرتبط است.
  • یک‌به‌چند: نشان‌دهنده رابطه‌ای است که در آن یک نهاد می‌تواند با چندین نهاد از نوع دیگر مرتبط باشد.
  • چند به چند: نشان‌دهنده رابطه‌ای است که در آن چندین نهاد از یک نوع می‌توانند با چندین نهاد از نوع دیگر مرتبط باشند. این کار معمولاً به جدول اتصال نیاز دارد.
  • روابط تودرتو بااستفاده از اشیای جاسازی‌شده: نشان‌دهنده رابطه‌ای است که در آن یک نهاد نهاد دیگری را به‌عنوان دارایی دربرمی‌گیرد، و این نهاد تودرتو می‌تواند نهادهای دیگری را نیز دربربگیرد. این از حاشیه‌نویسی @Embedded استفاده می‌کند.

از بین دو رویکرد انتخاب کنید

در Room، دو راه برای تعریف و پُرسمان کردن رابطه بین نهادها وجود دارد. می‌توانید از این موارد استفاده کنید:

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

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

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

استفاده از رویکرد کلاس داده میانی

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

برای مثال، می‌توانید UserBook کلاس داده‌ای را تعریف کنید تا کاربران کتابخانه را با کتاب‌های خاصی که امانت گرفته‌اند نشان دهد، و تابع پُرسمانی را تعریف کنید تا فهرستی از نمونه‌های UserBook را از پایگاه داده بازیابی کند:

@Dao
interface UserBookDao {
    @Query(
        """
        SELECT user.name AS userName, book.name AS bookName
        FROM user JOIN book ON user.id = book.user_id
        """
    )
    fun loadUserAndBookNames(): LiveData<List<UserBook>>
}

data class UserBook(val userName: String, val bookName: String)

از رویکرد نوع برگشتی چندنقشه‌ای استفاده کنید

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

برای مثال، تابع پُرسمان زیر نگاشت User و Book نمونه‌ها را برمی‌گرداند تا کاربران کتابخانه را با کتاب‌های خاصی که امانت گرفته‌اند نشان دهد:

@Query(
    """
    SELECT *
    FROM user JOIN book ON user.id = book.user_id
    """
)
suspend fun loadUserAndBookNames(): Map<User, List<Book>>

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

@Query(
    """
    SELECT user.*, COUNT(book.id) AS book_count
    FROM user LEFT JOIN book ON user.id = book.user_id
    GROUP BY user.id
    """
)
suspend fun loadUserAndBookCount(): Map<User, @MapColumn(columnName = "book_count") Int>

ایجاد کردن اشیای جاسازی‌شده

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

برای مثال، کلاس User شما می‌تواند شامل دارایی Address باشد که ترکیبی از دارایی‌های street،‏ city،‏ state، و postCode را نشان می‌دهد. برای ذخیره کردن ستون‌های ترکیبی به‌صورت جداگانه در جدول، دارایی Address را در کلاس User با @Embedded حاشیه‌نویسی کنید. تکه کد زیر این راه‌اندازی را نشان می‌دهد:

data class Address(
    val street: String?,
    val state: String?,
    val city: String?,
    @ColumnInfo(name = "post_code") val postCode: Int
)

@Entity
data class User(
    @PrimaryKey val id: Int,
    val firstName: String,
    @Embedded val address: Address?
)

جدول نشان‌دهنده شیء User سپس ستون‌هایی با نام‌های زیر دارد: id، firstName، street، state، city، و post_code.

اگر نهادی چندین دارایی جاسازی‌شده از یک نوع داشته باشد، می‌توانید با تنظیم دارایی prefix، هر ستون را منحصربه‌فرد نگه دارید. سپس Room مقدار ارائه‌شده را به ابتدای نام هر ستون در شیء جاسازی‌شده اضافه می‌کند.