בחירת סוגי הקשרים בין אובייקטים

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

סוגי הקשרים

החדר תומך בסוגי הקשר הבאים:

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

בחירה בין שתי גישות

ב-Room, יש שתי דרכים להגדיר ולשאול על קשר בין ישויות. אפשר להשתמש באחת מהאפשרויות הבאות:

  • מחלקת נתונים ביניים עם אובייקטים מוטמעים, או
  • שיטה של שאילתות יחסיות עם סוג החזרה multimap.

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

הגישה של מחלקת נתונים ביניים מאפשרת לכם להימנע מכתיבת שאילתות SQL מורכבות, אבל היא גם עלולה להוביל למורכבות מוגברת של הקוד כי היא דורשת מחלקות נתונים נוספות. בקיצור, הגישה של סוג ההחזרה multimap מחייבת את שאילתות ה-SQL לבצע יותר עבודה, והגישה של מחלקת הנתונים הביניים מחייבת את הקוד לבצע יותר עבודה.

שימוש בגישה של מחלקת נתונים ביניים

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

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

Kotlin

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

Java

@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, לא צריך להגדיר עוד מחלקות נתונים. במקום זאת, מגדירים סוג החזרה של multimap לשיטה על סמך מבנה המפה הרצוי, ומגדירים את הקשר בין הישויות ישירות בשאילתת ה-SQL.

לדוגמה, שיטת השאילתה הבאה מחזירה מיפוי של מופעים של User ושל Book כדי לייצג משתמשים בספרייה עם ספרים ספציפיים שהם השאילו:

Kotlin

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

Java

@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. קטע הקוד הבא מדגים את זה:

Kotlin

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

Java

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.

סרטונים

בלוגים