גישה לנתונים באמצעות רכיבי DAO של חדרים

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

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

המבנה של DAO

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

הקוד הבא הוא דוגמה ל-DAO פשוט שמגדיר שיטות (methods) הוספה, מחיקה ובחירה של אובייקטים מסוג User במסד הנתונים של Room:

Kotlin

@Dao
interface UserDao {
    @Insert
    fun insertAll(vararg users: User)

    @Delete
    fun delete(user: User)

    @Query("SELECT * FROM user")
    fun getAll(): List<User>
}

Java

@Dao
public interface UserDao {
    @Insert
    void insertAll(User... users);

    @Delete
    void delete(User user);

    @Query("SELECT * FROM user")
    List<User> getAll();
}

יש שני סוגים של שיטות DAO שמגדירות אינטראקציות עם מסדי נתונים:

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

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

שיטות נוחות

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

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

הוספה

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

Kotlin

@Dao
interface UserDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertUsers(vararg users: User)

    @Insert
    fun insertBothUsers(user1: User, user2: User)

    @Insert
    fun insertUsersAndFriends(user: User, friends: List<User>)
}

Java

@Dao
public interface UserDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    public void insertUsers(User... users);

    @Insert
    public void insertBothUsers(User user1, User user2);

    @Insert
    public void insertUsersAndFriends(User user, List<User> friends);
}

כל פרמטר ב-method @Insert חייב להיות מופע של חדר סיווג ישות נתונים עם הערות @Entity או אוסף של מופעי סיווג של ישות נתונים, שכל אחד מהם מצביע למסד נתונים. כשמתבצעת קריאה ל-method @Insert, כל אחד מהחדר מתווסף מופע של ישות שהועברה לטבלה המתאימה של מסד הנתונים.

אם ה-method @Insert מקבלת פרמטר יחיד, היא יכולה להחזיר long , שהוא הערך rowId החדש של הפריט שהוכנס. אם הפרמטר מערך או אוסף, ואז מחזירים מערך או אוסף של long ערכים במקום זאת, כאשר כל ערך הוא rowId של אחד מהערכים פריטים. למידע נוסף על החזרת ערכי rowId, יש לעיין בחומר העזר תיעוד של @Insert הערה והתיעוד של SQLite ל-Rowid טבלאות.

עדכון

ההערה @Update מאפשרת להגדיר שיטות שמעדכנות שורות מסוימות בטבלה של מסד נתונים. מוצא חן בעיניי @Insert methods, methods של @Update מקבלות מופעים של ישויות נתונים כפרמטרים. הקוד הבא מציג דוגמה ל-method @Update שמנסה מעדכנים אובייקט User אחד או יותר במסד הנתונים:

Kotlin

@Dao
interface UserDao {
    @Update
    fun updateUsers(vararg users: User)
}

Java

@Dao
public interface UserDao {
    @Update
    public void updateUsers(User... users);
}

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

שיטת @Update יכולה להחזיר ערך int שמציין את המספר מתוך השורות שעודכנו בהצלחה.

מחיקה

ההערה @Delete מאפשרת להגדיר שיטות למחיקת שורות ספציפיות מטבלה של מסד נתונים. מוצא חן בעיניי @Insert methods, methods של @Delete מקבלות מופעים של ישויות נתונים כפרמטרים. הקוד הבא מציג דוגמה ל-method @Delete שמנסה מוחקים אובייקט User אחד או יותר ממסד הנתונים:

Kotlin

@Dao
interface UserDao {
    @Delete
    fun deleteUsers(vararg users: User)
}

Java

@Dao
public interface UserDao {
    @Delete
    public void deleteUsers(User... users);
}

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

השיטה @Delete יכולה להחזיר ערך int שמציין את מספר שורות שנמחקו בהצלחה.

שיטות השאילתה

ההערה @Query מאפשרת לכתוב הצהרות SQL ולחשוף אותן כשיטות DAO. שימוש בשיטות השאילתה האלה כדי ממסד הנתונים של האפליקציה או כשצריך לבצע פעולות מורכבות יותר הוספה, עדכונים ומחיקות.

חדר מאמת שאילתות SQL בזמן הקומפילציה. המשמעות היא שאם יש בעיה בשאילתה שלך, תתקבל שגיאת הידור (compilation) במקום כשל בסביבת זמן הריצה.

שאילתות פשוטות

הקוד הבא מגדיר שיטה שמשתמשת בשאילתת SELECT פשוטה כדי להחזיר כל האובייקטים User במסד הנתונים:

Kotlin

@Query("SELECT * FROM user")
fun loadAllUsers(): Array<User>

Java

@Query("SELECT * FROM user")
public User[] loadAllUsers();

בקטעים הבאים מוסבר איך לשנות את הדוגמה הזו לשימוש רגיל במקרים שונים.

החזרת קבוצת משנה של עמודות טבלה

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

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

Kotlin

data class NameTuple(
    @ColumnInfo(name = "first_name") val firstName: String?,
    @ColumnInfo(name = "last_name") val lastName: String?
)

Java

public class NameTuple {
    @ColumnInfo(name = "first_name")
    public String firstName;

    @ColumnInfo(name = "last_name")
    @NonNull
    public String lastName;
}

לאחר מכן אפשר להחזיר אובייקט פשוט משיטת השאילתה:

Kotlin

@Query("SELECT first_name, last_name FROM user")
fun loadFullName(): List<NameTuple>

Java

@Query("SELECT first_name, last_name FROM user")
public List<NameTuple> loadFullName();

החדר מבין שהשאילתה מחזירה ערכים של first_name ושל last_name עמודות, ושאפשר למפות את הערכים האלה לשדות כיתה אחת (NameTuple). אם השאילתה מחזירה עמודה שלא ממופה לשדה מסוים. באובייקט שהמוחזר, מופיעה אזהרה בחדר.

העברת פרמטרים פשוטים לשאילתה

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

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

Kotlin

@Query("SELECT * FROM user WHERE age > :minAge")
fun loadAllUsersOlderThan(minAge: Int): Array<User>

Java

@Query("SELECT * FROM user WHERE age > :minAge")
public User[] loadAllUsersOlderThan(int minAge);

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

Kotlin

@Query("SELECT * FROM user WHERE age BETWEEN :minAge AND :maxAge")
fun loadAllUsersBetweenAges(minAge: Int, maxAge: Int): Array<User>

@Query("SELECT * FROM user WHERE first_name LIKE :search " +
       "OR last_name LIKE :search")
fun findUserWithName(search: String): List<User>

Java

@Query("SELECT * FROM user WHERE age BETWEEN :minAge AND :maxAge")
public User[] loadAllUsersBetweenAges(int minAge, int maxAge);

@Query("SELECT * FROM user WHERE first_name LIKE :search " +
       "OR last_name LIKE :search")
public List<User> findUserWithName(String search);

העברת אוסף של פרמטרים לשאילתה

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

לדוגמה, הקוד הבא מגדיר שיטה שמחזירה מידע על כל המשתמשים מתת-אזורים של אזורים:

Kotlin

@Query("SELECT * FROM user WHERE region IN (:regions)")
fun loadUsersFromRegions(regions: List<String>): List<User>

Java

@Query("SELECT * FROM user WHERE region IN (:regions)")
public List<User> loadUsersFromRegions(List<String> regions);

שליחת שאילתה לגבי כמה טבלאות

יכול להיות שבחלק מהשאילתות נדרשת גישה לכמה טבלאות כדי לחשב תוצאה אחת. אפשר להשתמש בתנאי JOIN בשאילתות SQL כדי להפנות ליותר מ- טבלה אחת.

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

Kotlin

@Query(
    "SELECT * FROM book " +
    "INNER JOIN loan ON loan.book_id = book.id " +
    "INNER JOIN user ON user.id = loan.user_id " +
    "WHERE user.name LIKE :userName"
)
fun findBooksBorrowedByNameSync(userName: String): List<Book>

Java

@Query("SELECT * FROM book " +
       "INNER JOIN loan ON loan.book_id = book.id " +
       "INNER JOIN user ON user.id = loan.user_id " +
       "WHERE user.name LIKE :userName")
public List<Book> findBooksBorrowedByNameSync(String userName);

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

Kotlin

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

    // You can also define this class in a separate file.
    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();

   // You can also define this class in a separate file, as long as you add the
   // "public" access modifier.
   static class UserBook {
       public String userName;
       public String bookName;
   }
}

החזרת מיפוי מרובה

בחדר 2.4 ואילך, אתם יכולים גם להריץ שאילתות על עמודות מכמה טבלאות ללא הגדרה של סיווג נתונים נוסף על ידי כתיבת שיטות שאילתה שמחזירות סוג נתונים multimap.

קחו לדוגמה את הדוגמה שבקטע הרצת שאילתות על מספר טבלאות. במקום להחזיר רשימת מופעים של קטגוריית נתונים מותאמת אישית שמכילה צמדים של User ו-Book מופעים, אפשר להחזיר מיפוי של 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();

אם שיטת השאילתה מחזירה מיפוי מרובה, אפשר לכתוב שאילתות שמשתמשות ב- GROUP BY תנאים, כך שתוכלו לנצל את היכולות של SQL חישובים וסינון מתקדמים. לדוגמה, אפשר לשנות את שיטה loadUserAndBookNames() להחזרת משתמשים עם שלושה ספרים או יותר עשה צ'ק-אאוט:

Kotlin

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

Java

@Query(
    "SELECT * FROM user" +
    "JOIN book ON user.id = book.user_id" +
    "GROUP BY user.name WHERE COUNT(book.id) >= 3"
)
public Map<User, List<Book>> loadUserAndBookNames();

אם לא צריך למפות אובייקטים שלמים, אפשר גם להחזיר מיפויים בין עמודות ספציפיות בשאילתה שלך keyColumn ו- valueColumn מאפיינים בהערה @MapInfo שיטת השאילתה:

Kotlin

@MapInfo(keyColumn = "userName", valueColumn = "bookName")
@Query(
    "SELECT user.name AS username, book.name AS bookname FROM user" +
    "JOIN book ON user.id = book.user_id"
)
fun loadUserAndBookNames(): Map<String, List<String>>

Java

@MapInfo(keyColumn = "userName", valueColumn = "bookName")
@Query(
    "SELECT user.name AS username, book.name AS bookname FROM user" +
    "JOIN book ON user.id = book.user_id"
)
public Map<String, List<String>> loadUserAndBookNames();

סוגי החזרה מיוחדים

החדר מציע כמה סוגי החזרה מיוחדים לשילוב עם API אחר. של הספריות.

שאילתות עם חלוקה לדפים באמצעות ספריית הדפים

חדר תומך בשאילתות בחלוקה לדפים באמצעות שילוב עם החלוקה לדפים לספרייה. בחדר 2.3.0-alpha01 ו גבוהה יותר, DAOs יכולים להחזיר PagingSource אובייקטים לשימוש באמצעות מעבר מספר 3.

Kotlin

@Dao
interface UserDao {
  @Query("SELECT * FROM users WHERE label LIKE :query")
  fun pagingSource(query: String): PagingSource<Int, User>
}

Java

@Dao
interface UserDao {
  @Query("SELECT * FROM users WHERE label LIKE :query")
  PagingSource<Integer, User> pagingSource(String query);
}

למידע נוסף על בחירת פרמטרים של סוג עבור PagingSource, ניתן לעיין במאמר בחירת מפתח וערך .

גישה ישירה לסמן

אם הלוגיקה של האפליקציה מחייבת גישה ישירה לשורות ההחזרה, אפשר לכתוב שיטות DAO להחזרת Cursor כפי שאפשר לראות בדוגמה הבאה:

Kotlin

@Dao
interface UserDao {
    @Query("SELECT * FROM user WHERE age > :minAge LIMIT 5")
    fun loadRawUsersOlderThan(minAge: Int): Cursor
}

Java

@Dao
public interface UserDao {
    @Query("SELECT * FROM user WHERE age > :minAge LIMIT 5")
    public Cursor loadRawUsersOlderThan(int minAge);
}

מקורות מידע נוספים

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

דוגמיות

שיעורי Lab