از آنجا که SQLite یک پایگاه داده رابطهای است، میتوانید روابط بین موجودیتها را تعریف کنید. اما در حالی که اکثر کتابخانههای نگاشت شیء-رابطهای به اشیاء موجودیت اجازه میدهند به یکدیگر ارجاع دهند، Room صراحتاً این کار را ممنوع میکند. برای آشنایی با استدلال فنی پشت این تصمیم، به بخش «درک اینکه چرا Room اجازه ارجاع به اشیاء را نمیدهد» مراجعه کنید.
انواع روابط
روم از انواع روابط زیر پشتیبانی میکند:
- یک به یک : نشاندهنده رابطهای است که در آن یک موجودیت واحد با موجودیت واحد دیگری مرتبط است.
- یک به چند : نشاندهنده رابطهای است که در آن یک موجودیت واحد میتواند با چندین موجودیت از نوع دیگر مرتبط باشد.
- چند به چند : نشاندهنده رابطهای است که در آن چندین موجودیت از یک نوع میتوانند به چندین موجودیت از نوع دیگر مرتبط باشند. این معمولاً به یک جدول اتصال نیاز دارد.
- روابط تو در تو (با استفاده از اشیاء تعبیه شده) : رابطهای را نشان میدهد که در آن یک موجودیت شامل موجودیت دیگری به عنوان فیلد است و این موجودیت تو در تو میتواند شامل موجودیتهای دیگری نیز باشد. این از حاشیهنویسی
@Embeddedاستفاده میکند.
انتخاب بین دو رویکرد
در Room، دو روش برای تعریف و پرسوجوی رابطه بین موجودیتها وجود دارد. میتوانید از هر یک از موارد زیر استفاده کنید:
- یک کلاس داده میانی با اشیاء تعبیه شده، یا
- یک روش پرسوجوی رابطهای با نوع بازگشتی چندنقشهای.
اگر دلیل خاصی برای استفاده از کلاسهای داده میانی ندارید، توصیه میکنیم از رویکرد نوع بازگشتی multimap استفاده کنید. برای کسب اطلاعات بیشتر در مورد این رویکرد، به Return a multimap مراجعه کنید.
رویکرد کلاس داده میانی به شما امکان میدهد از نوشتن کوئریهای پیچیده SQL اجتناب کنید، اما میتواند منجر به افزایش پیچیدگی کد نیز شود زیرا به کلاسهای داده اضافی نیاز دارد. به طور خلاصه، رویکرد نوع بازگشتی multimap مستلزم آن است که کوئریهای SQL شما کار بیشتری انجام دهند و رویکرد کلاس داده میانی مستلزم آن است که کد شما کار بیشتری انجام دهد.
از رویکرد کلاس داده میانی استفاده کنید
در رویکرد کلاس داده میانی، شما یک کلاس داده تعریف میکنید که رابطه بین موجودیتهای Room شما را مدلسازی میکند. این کلاس داده، جفتسازیهای بین نمونههای یک موجودیت و نمونههای موجودیت دیگر را به عنوان اشیاء تعبیهشده نگه میدارد. سپس متدهای پرسوجوی شما میتوانند نمونههایی از این کلاس داده را برای استفاده در برنامه شما برگردانند.
برای مثال، میتوانید یک کلاس داده UserBook تعریف کنید تا کاربران کتابخانه را با کتابهای خاصِ امانت گرفته شده نمایش دهد، و یک متد پرسوجو برای بازیابی لیستی از نمونههای UserBook از پایگاه داده تعریف کنید:
کاتلین
@Dao
interface UserBookDao {
@Query(
"SELECT user.name AS userName, book.name AS bookName " +
"FROM user, book " +
"WHERE user.id = book.user_id"
)
fun loadUserAndBookNames(): LiveData<List<UserBook>>
}
data class UserBook(val userName: String?, val bookName: String?)
جاوا
@Dao
public interface UserBookDao {
@Query("SELECT user.name AS userName, book.name AS bookName " +
"FROM user, book " +
"WHERE user.id = book.user_id")
public LiveData<List<UserBook>> loadUserAndBookNames();
}
public class UserBook {
public String userName;
public String bookName;
}
از رویکرد انواع بازگشتی چندنقشهای استفاده کنید
در رویکرد نوع بازگشتی multimap، نیازی به تعریف هیچ کلاس داده اضافی ندارید. در عوض، یک نوع بازگشتی multimap برای متد خود بر اساس ساختار نقشه مورد نظر خود تعریف میکنید و رابطه بین موجودیتهای خود را مستقیماً در کوئری SQL خود تعریف میکنید.
برای مثال، متد پرسوجوی زیر، نگاشتی از نمونههای User و Book را برمیگرداند تا کاربران کتابخانه را با کتابهای خاصِ تحویل داده شده نشان دهد:
کاتلین
@Query(
"SELECT * FROM user" +
"JOIN book ON user.id = book.user_id"
)
fun loadUserAndBookNames(): Map<User, List<Book>>
جاوا
@Query(
"SELECT * FROM user" +
"JOIN book ON user.id = book.user_id"
)
public Map<User, List<Book>> loadUserAndBookNames();
ایجاد اشیاء جاسازی شده
گاهی اوقات، شما میخواهید یک موجودیت یا شیء داده را به عنوان یک کل منسجم در منطق پایگاه داده خود بیان کنید، حتی اگر شیء شامل چندین فیلد باشد. در این شرایط، میتوانید از حاشیهنویسی @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?
)
جاوا
public class Address {
public String street;
public String state;
public String city;
@ColumnInfo(name = "post_code") public int postCode;
}
@Entity
public class User {
@PrimaryKey public int id;
public String firstName;
@Embedded public Address address;
}
جدولی که نشاندهندهی یک شیء User است، شامل ستونهایی با نامهای زیر خواهد بود: id ، firstName ، street ، state ، city و post_code .
اگر یک موجودیت چندین فیلد تعبیهشده از یک نوع داشته باشد، میتوانید با تنظیم ویژگی prefix ، هر ستون را منحصر به فرد نگه دارید. سپس Room مقدار ارائه شده را به ابتدای نام هر ستون در شیء تعبیهشده اضافه میکند.
منابع اضافی
برای کسب اطلاعات بیشتر در مورد تعریف روابط بین موجودیتها در Room، به منابع تکمیلی زیر مراجعه کنید.
ویدیوها
- ویژگیهای جدید Room (نشست توسعهدهندگان اندروید '19)