התייחסות לנתונים מורכבים באמצעות 'חדר'

התכונה 'חדר' מספקת פונקציונליות להמרה בין סוגים פרימיטיביים ומקיפים אבל היא לא מאפשרת הפניות אובייקטים בין ישויות. המסמך הזה מסבירה איך להשתמש בממירים של סוגי המשתנים ולמה Room לא תומך באובייקטים הפניות.

שימוש בממירים

לפעמים צריך שהאפליקציה שלך תאחסן סוג נתונים מותאם אישית במסד נתונים יחיד עמודה. כדי לתמוך בסוגים מותאמים אישית, אתם צריכים לספק ממירים של סוגי המרות. שיטות שמסבירות ל- Room איך להמיר סוגים מותאמים אישית לסוגים מוכרים החדר יכול להימשך. אתה מזהה ממירים לפי סוג @TypeConverter.

נניח שצריך לשמור מופעים של Date מסד הנתונים Room. החדר לא יודע איך לשמור Date אובייקטים, לכן צריך כדי להגדיר סוגי ממירים:

Kotlin

class Converters {
  @TypeConverter
  fun fromTimestamp(value: Long?): Date? {
    return value?.let { Date(it) }
  }

  @TypeConverter
  fun dateToTimestamp(date: Date?): Long? {
    return date?.time?.toLong()
  }
}

Java

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. מכיוון שהחדר יודע איך לשמור על Long אובייקטים, הוא יכול להשתמש ממירים אלה כדי לשמור Date אובייקטים.

בשלב הבא, מוסיפים את @TypeConverters הערה לכיתה AppDatabase כדי ש- Room ידע על הממיר המחלקה שהגדרתם:

Kotlin

@Database(entities = [User::class], version = 1)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
  abstract fun userDao(): UserDao
}

Java

@Database(entities = {User.class}, version = 1)
@TypeConverters({Converters.class})
public abstract class AppDatabase extends RoomDatabase {
  public abstract UserDao userDao();
}

כשמוגדרים ממירים מהסוג הזה, אפשר להשתמש בסוג המותאם אישית של ישויות ושל dAOs בדיוק כמו שמשתמשים בסוגים ראשוניים:

Kotlin

@Entity
data class User(private val birthday: Date?)

@Dao
interface UserDao {
  @Query("SELECT * FROM user WHERE birthday = :targetDate")
  fun findUsersBornOnDate(targetDate: Date): List<User>
}

Java

@Entity
public class User {
  private Date birthday;
}

@Dao
public interface UserDao {
  @Query("SELECT * FROM user WHERE birthday = :targetDate")
  List<User> findUsersBornOnDate(Date targetDate);
}

בדוגמה הזו, חדר יכול להשתמש בממיר הסוג המוגדר בכל מקום, כי הוספת הערות ל-AppDatabase עם @TypeConverters. עם זאת, אפשר גם להשתמש בסוג ההיקף ממירים לישויות או אדמינים ספציפיים (DAOs) על ידי הוספת הערות ל@Entity או ל@Dao עם @TypeConverters.

אתחול הממיר של סוג הבקרה

בדרך כלל, חדר מטפל עבורכם ביצירת ממירים של סוגים. אבל, לפעמים לפעמים ייתכן שתצטרכו להעביר יחסי תלות נוספים לממיר סוג ההמרה כלומר, אתם צריכים שהאפליקציה שלכם תוכל לשלוט ישירות באתחול מסוג ממירים. במקרה כזה, כדאי להוסיף הערות למחלקה של הממיר עם @ProvidedTypeConverter:

Kotlin

@ProvidedTypeConverter
class ExampleConverter {
  @TypeConverter
  fun StringToExample(string: String?): ExampleType? {
    ...
  }

  @TypeConverter
  fun ExampleToString(example: ExampleType?): String? {
    ...
  }
}

Java

@ProvidedTypeConverter
public class ExampleConverter {
  @TypeConverter
  public Example StringToExample(String string) {
    ...
  }

  @TypeConverter
  public String ExampleToString(Example example) {
    ...
  }
}

לאחר מכן, בנוסף להצהרה על שיעור ההמרה של @TypeConverters, משתמשים ה RoomDatabase.Builder.addTypeConverter() כדי להעביר מופע של מחלקת הממירים אל RoomDatabase Builder:

Kotlin

val db = Room.databaseBuilder(...)
  .addTypeConverter(exampleConverterInstance)
  .build()

Java

AppDatabase db = Room.databaseBuilder(...)
  .addTypeConverter(exampleConverterInstance)
  .build();

למה אי אפשר להשתמש בהפניות לאובייקטים בחדר

נקודות מרכזיות: חדר לא מאפשר הפניות לאובייקטים בין סיווגי ישויות. במקום זאת, לבקש במפורש את הנתונים שדרושים לאפליקציה.

מיפוי קשרים ממסד נתונים למודל האובייקט המתאים הוא ועובד היטב בצד השרת. גם כשהתוכנית נטענת בזמן הגישה אליהם, השרת עדיין פועל היטב.

עם זאת, בצד הלקוח, לא ניתן לבצע טעינה מדורגת מהסוג הזה, היא מתרחשת בדרך כלל ב-thread של ממשק המשתמש, ולבצע שאילתה על מידע על הדיסק בממשק המשתמש thread יוצר בעיות משמעותיות בביצועים. בדרך כלל ה-thread של ממשק המשתמש כולל כ-16 אלפיות השנייה כדי לחשב ולצייר פריסה מעודכנת של פעילות, כך שגם אם לוקח רק 5 אלפיות השנייה, עדיין סביר להניח שייגמר הזמן כדי שהאפליקציה שלך תסתיים משרטטים את המסגרת, באופן שיוצר תקלות חזותיות בולטות. השאילתה יכולה להימשך אפילו נדרשת יותר זמן להשלמת העסקה אם מתבצעת עסקה נפרדת במקביל, או אם במכשיר פועלות משימות אחרות שצורכות הרבה דיסק. אם לא משתמשים אבל האפליקציה מאחזרת יותר נתונים ממה שהיא צריכה, דבר שיוצר זיכרון בעיות צריכה.

מיפויים של קשרים בין אובייקטים בדרך כלל משאירים את ההחלטה הזו למפתחים, הם יכולים לעשות את מה שהכי מתאים לתרחישים לדוגמה של האפליקציה שלהם. בדרך כלל מפתחים מחליטים לשתף את המודל בין האפליקציה שלהם לבין ממשק המשתמש. הפתרון הזה לא עם זאת, מכיוון שממשק המשתמש משתנה עם הזמן, המודל המשותף יוצרת בעיות שקשה למפתחים לחזות ולנפות באגים.

לדוגמה, נבחן ממשק משתמש שטוען רשימה של Book אובייקטים, עם כל ספר עם אובייקט Author. יכול להיות שבשלב הראשון תעצבו את השאילתות בטעינה כדי שהמופעים של Book יאחזרו את המחבר. האחזור הראשון של השדה author שולח שאילתה למסד הנתונים. זמן מה לאחר מכן אתה מבין עליך להציג את שם המחבר גם בממשק המשתמש של האפליקציה. יש לך אפשרות לגשת מספיק בקלות, כפי שמוצג בקטע הקוד הבא:

Kotlin

authorNameTextView.text = book.author.name

Java

authorNameTextView.setText(book.getAuthor().getName());

עם זאת, השינוי הזה לכאורה תמים גורם ליצירת שאילתות לגבי הטבלה Author בשרשור הראשי.

אם תשאלו מראש את פרטי המחבר/ת, יהיה קשה יותר לשנות אותו באופן שבו הנתונים נטענים אם אתם לא צריכים יותר את הנתונים האלה. לדוגמה, אם ממשק המשתמש כבר לא צריך להציג מידע על Author, האפליקציה נטענת ביעילות נתונים שכבר לא מוצגים, תוך בזבוז מקום זיכרון יקר. של האפליקציה שלך היעילות יורדת עוד יותר אם המחלקה Author מפנה לטבלה אחרת, כמו Books.

כדי להפנות לכמה ישויות בו-זמנית באמצעות 'חדר', צריך ליצור בשדה POJO שמכיל כל ישות, כותבים שאילתה שמצרפת את השאילתה בטבלאות. המודל הזה מובנה היטב, שמשלב את השאילתה החזקה של החדר. יכולות אימות מאפשרות לאפליקציה לצרוך פחות משאבים בזמן הטעינה , לשיפור הביצועים של האפליקציה וחוויית המשתמש.