Room عملکردی را برای تبدیل بین انواع اولیه و جعبهای ارائه میکند، اما اجازه ارجاع به شی بین موجودیتها را نمیدهد. این سند نحوه استفاده از مبدلهای نوع و اینکه چرا Room از ارجاعات شی پشتیبانی نمیکند، توضیح میدهد.
از مبدل های نوع استفاده کنید
گاهی اوقات، شما نیاز دارید که برنامه خود یک نوع داده سفارشی را در یک ستون پایگاه داده ذخیره کند. شما از انواع سفارشی با ارائه مبدلهای نوع پشتیبانی میکنید، که روشهایی هستند که به اتاق میگویند چگونه انواع سفارشی را به و از انواع شناختهشدهای که Room میتواند ادامه دهد، تبدیل کند. شما مبدل های نوع را با استفاده از حاشیه نویسی @TypeConverter
شناسایی می کنید.
فرض کنید باید نمونههایی از Date
در پایگاه داده اتاق خود نگه دارید. Room نمی داند چگونه اشیاء Date
حفظ کند، بنابراین باید مبدل های نوع را تعریف کنید:
کاتلین
class Converters { @TypeConverter fun fromTimestamp(value: Long?): Date? { return value?.let { Date(it) } } @TypeConverter fun dateToTimestamp(date: Date?): Long? { return date?.time?.toLong() } }
جاوا
public class Converters { @TypeConverter public static Date fromTimestamp(Long value) { return value == null ? null : new Date(value); } @TypeConverter public static Long dateToTimestamp(Date date) { return date == null ? null : date.getTime(); } }
این مثال دو روش مبدل نوع را تعریف میکند: یکی که یک شی Date
را به یک شی Long
تبدیل میکند و دیگری که تبدیل معکوس را از Long
به Date
انجام میدهد. از آنجایی که Room می داند چگونه اشیاء Long
را حفظ کند، می تواند از این مبدل ها برای ماندگاری اشیاء Date
استفاده کند.
سپس، حاشیهنویسی @TypeConverters
به کلاس AppDatabase
اضافه میکنید تا Room از کلاس مبدلی که تعریف کردهاید مطلع شود:
کاتلین
@Database(entities = [User::class], version = 1) @TypeConverters(Converters::class) abstract class AppDatabase : RoomDatabase() { abstract fun userDao(): UserDao }
جاوا
@Database(entities = {User.class}, version = 1) @TypeConverters({Converters.class}) public abstract class AppDatabase extends RoomDatabase { public abstract UserDao userDao(); }
با تعریف این مبدلهای نوع، میتوانید از نوع سفارشی خود در موجودیتها و DAOهای خود استفاده کنید، همانطور که از انواع اولیه استفاده میکنید:
کاتلین
@Entity data class User(private val birthday: Date?) @Dao interface UserDao { @Query("SELECT * FROM user WHERE birthday = :targetDate") fun findUsersBornOnDate(targetDate: Date): List<User> }
جاوا
@Entity public class User { private Date birthday; } @Dao public interface UserDao { @Query("SELECT * FROM user WHERE birthday = :targetDate") List<User> findUsersBornOnDate(Date targetDate); }
در این مثال، Room میتواند از مبدل نوع تعریفشده در همه جا استفاده کند، زیرا شما AppDatabase
با @TypeConverters
حاشیهنویسی کردهاید. با این حال، میتوانید با حاشیهنویسی کلاسهای @Entity
یا @Dao
خود با @TypeConverters
، مبدلهای نوع دامنه را به موجودیتها یا DAOهای خاص تبدیل کنید.
مقداردهی اولیه مبدل نوع کنترل
معمولاً اتاق نمونهسازی مبدلهای نوع را برای شما انجام میدهد. با این حال، گاهی اوقات ممکن است لازم باشد وابستگیهای اضافی را به کلاسهای مبدل نوع خود منتقل کنید، به این معنی که به برنامه خود نیاز دارید تا مستقیماً مقداردهی اولیه مبدلهای نوع خود را کنترل کند. در این صورت، کلاس مبدل خود را با @ProvidedTypeConverter
حاشیه نویسی کنید:
کاتلین
@ProvidedTypeConverter class ExampleConverter { @TypeConverter fun StringToExample(string: String?): ExampleType? { ... } @TypeConverter fun ExampleToString(example: ExampleType?): String? { ... } }
جاوا
@ProvidedTypeConverter public class ExampleConverter { @TypeConverter public Example StringToExample(String string) { ... } @TypeConverter public String ExampleToString(Example example) { ... } }
سپس، علاوه بر اعلام کلاس مبدل خود در @TypeConverters
، از متد RoomDatabase.Builder.addTypeConverter()
برای ارسال نمونه ای از کلاس مبدل خود به سازنده RoomDatabase
استفاده کنید:
کاتلین
val db = Room.databaseBuilder(...) .addTypeConverter(exampleConverterInstance) .build()
جاوا
AppDatabase db = Room.databaseBuilder(...) .addTypeConverter(exampleConverterInstance) .build();
درک کنید که چرا Room به اشیاء ارجاع نمی دهد
نکته کلیدی: Room ارجاع شی بین کلاس های موجودیت را ممنوع می کند. در عوض، باید صریحاً دادههایی را که برنامه شما به آن نیاز دارد درخواست کنید.
نگاشت روابط از یک پایگاه داده به مدل شی مربوطه یک روش معمول است و در سمت سرور بسیار خوب عمل می کند. حتی زمانی که برنامه فیلدها را با دسترسی به آنها بارگیری می کند، سرور همچنان عملکرد خوبی دارد.
با این حال، در سمت کلاینت، این نوع بارگذاری تنبل امکان پذیر نیست، زیرا معمولاً در رشته UI رخ می دهد، و جستجوی اطلاعات روی دیسک در رشته UI مشکلات عملکرد قابل توجهی ایجاد می کند. رشته UI معمولاً حدود 16 میلیثانیه برای محاسبه و ترسیم طرحبندی بهروز شده یک فعالیت دارد، بنابراین حتی اگر یک پرسوجو فقط 5 میلیثانیه طول بکشد، باز هم احتمال دارد برنامه شما برای ترسیم فریم زمان تمام شود و اشکالات بصری قابل توجهی ایجاد کند. اگر تراکنش جداگانه ای به صورت موازی در حال اجرا باشد، یا اگر دستگاه در حال اجرای سایر وظایف فشرده دیسک باشد، این پرس و جو ممکن است زمان بیشتری را صرف کند. با این حال، اگر از بارگذاری تنبل استفاده نمی کنید، برنامه شما داده های بیشتری از نیاز خود دریافت می کند و مشکلاتی در مصرف حافظه ایجاد می کند.
نگاشتهای رابطهای شی معمولاً این تصمیم را به توسعهدهندگان واگذار میکنند تا بتوانند بهترین کار را برای موارد استفاده برنامه خود انجام دهند. توسعه دهندگان معمولاً تصمیم می گیرند مدل را بین برنامه خود و رابط کاربری به اشتراک بگذارند. با این حال، این راه حل به خوبی مقیاس بندی نمی شود، زیرا با تغییر رابط کاربری در طول زمان، مدل مشترک مشکلاتی را ایجاد می کند که پیش بینی و اشکال زدایی آن برای توسعه دهندگان دشوار است.
به عنوان مثال، رابط کاربری را در نظر بگیرید که فهرستی از اشیاء Book
را بارگیری میکند و هر کتاب دارای یک شیء Author
است. ممکن است ابتدا درخواست های خود را طوری طراحی کنید که از بارگذاری تنبل استفاده کنید تا نمونه هایی از Book
نویسنده را بازیابی کند. اولین بازیابی فیلد author
، پایگاه داده را پرس و جو می کند. مدتی بعد، متوجه میشوید که باید نام نویسنده را در رابط کاربری برنامه خود نیز نمایش دهید. همانطور که در قطعه کد زیر نشان داده شده است، می توانید به راحتی به این نام دسترسی پیدا کنید:
کاتلین
authorNameTextView.text = book.author.name
جاوا
authorNameTextView.setText(book.getAuthor().getName());
با این حال، این تغییر به ظاهر بیگناه باعث میشود که جدول Author
در موضوع اصلی مورد پرسش قرار گیرد.
اگر اطلاعات نویسنده را زودتر از موعد جستجو کنید، تغییر نحوه بارگیری داده ها در صورتی که دیگر به آن داده ها نیاز نداشته باشید دشوار می شود. به عنوان مثال، اگر رابط کاربری برنامه شما دیگر نیازی به نمایش اطلاعات Author
نداشته باشد، برنامه شما به طور موثر داده هایی را که دیگر نمایش نمی دهد بارگیری می کند و فضای ارزشمند حافظه را هدر می دهد. اگر کلاس Author
به جدول دیگری مانند Books
ارجاع دهد، کارایی برنامه شما حتی بیشتر کاهش می یابد.
برای ارجاع همزمان چندین موجودیت با استفاده از Room، به جای آن یک POJO ایجاد میکنید که حاوی هر موجودیت است، سپس یک کوئری مینویسید که به جداول مربوطه میپیوندد. این مدل به خوبی ساختار یافته، همراه با قابلیتهای قوی اعتبارسنجی پرس و جوی Room، به برنامه شما اجازه میدهد منابع کمتری را هنگام بارگیری داده مصرف کند و عملکرد برنامه و تجربه کاربری شما را بهبود بخشد.