الوصول إلى البيانات باستخدام وحدات إدارة البيانات (DAOs) للغرفة

عند استخدام مكتبة الاحتفاظ بالبيانات في الغرفة لتخزين بيانات تطبيقك، بالبيانات المخزنة من خلال تحديد كائنات الوصول إلى البيانات، أو DAO. كل مقياس DAO على طرق توفر وصولاً مجردًا إلى قاعدة بيانات التطبيق. التجميع ينشئ الغرفة تلقائيًا عمليات تنفيذ DAO التي تحددها.

من خلال استخدام DAO للوصول إلى قاعدة بيانات التطبيق بدلاً من أدوات إنشاء الطلبات أو توجيه فيمكنك الحفاظ على فصل المخاوف ذات الصلة، وهو هندسة معمارية مهمة المبدأ. تسهّل عليك أنظمة DAO أيضًا محاكاة الوصول إلى قاعدة البيانات عندما اختبار تطبيقك

تحليل جهاز DAO

يمكنك تعريف كل DAO إما كواجهة أو فئة مجردة. للإصدارات الأساسية: حالات الاستخدام، فعادةً ما تستخدم واجهة. في كلتا الحالتين، يجب عليك دائمًا أضِف تعليقات توضيحية إلى رموز DAO الخاصة بك باستخدام @Dao. أجهزة DAO لا تمتلك خصائص، لكنها تحدد طريقة واحدة أو أكثر للتفاعل مع البيانات في قاعدة بيانات التطبيق.

التعليمة البرمجية التالية هي مثال على DAO بسيط يحدد طرق إدراج عناصر User وحذفها واختيارها في قاعدة بيانات الغرف:

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);
}

يجب أن تكون كل معلمة لطريقة @Insert إما مثالاً على غرفة فئة كيان البيانات التي تمت إضافة تعليقات توضيحية إليها @Entity أو مجموعة من الحالات لفئة كيان البيانات، ويشير إلى قاعدة بيانات. عند استدعاء طريقة @Insert، تُدرِج الغرفة كل منها. مرر مثيل الكيان إلى جدول قاعدة البيانات المقابل.

إذا تلقت طريقة @Insert معلَمة واحدة، يمكنها عرض long وهي قيمة rowId الجديدة للعنصر المدرج. إذا كانت المعلمة صفيفة أو مجموعة، ثم تُرجع صفيفًا أو مجموعة من long قيمة بدلاً من ذلك، مع جعل كل قيمة هي rowId لإحدى القيم عناصر. لمزيد من المعلومات حول عرض قيم rowId، يمكنك الاطّلاع على المرجع. مستند حول @Insert التعليق التوضيحي ووثائق SQLite لمعرّف الصف الجداول.

تعديل

يتيح لك التعليق التوضيحي @Update تحديد الطرق التي تعمل على تحديث صفوف معينة في جدول قاعدة بيانات. أعجبني @Insert طريقة، تقبل طريقة واحدة (@Update) حالات كيان البيانات كمَعلمات. يوضح الرمز التالي مثالاً على طريقة @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 طريقة، تقبل طريقة واحدة (@Delete) حالات كيان البيانات كمَعلمات. يوضح الرمز التالي مثالاً على طريقة @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 في وقت التجميع. هذا يعني أنه إذا كانت هناك مشكلة مع طلب البحث، يحدث خطأ في التحويل البرمجي بدلاً من إخفاق بيئة التشغيل.

طلبات بحث بسيطة

يحدد الرمز التالي طريقة تستخدم استعلام SELECT بسيط لعرض كافة كائنات User في قاعدة البيانات:

Kotlin

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

Java

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

توضح الأقسام التالية كيفية تعديل هذا المثال للاستخدام النموذجي. الحالات.

إرجاع مجموعة فرعية من أعمدة الجدول

في معظم الأحيان، تحتاج فقط إلى عرض مجموعة فرعية من الأعمدة من الجدول التي تستعلم عنها. على سبيل المثال، قد تعرض واجهة المستخدم الصفحة الأولى فقط اسم العائلة للمستخدم بدلاً من كل التفاصيل المتعلقة بهذا المستخدم. للحفظ الموارد وتبسيط تنفيذ طلب البحث، فما عليك سوى الاستعلام عن الحقول التي تحتاجها.

تتيح لك الغرفة عرض كائن بسيط من أي من طلبات البحث الخاصة بك طالما يمكنك تعيين مجموعة أعمدة النتائج على الكائن الذي تم إرجاعه. على سبيل المثال، يمكن تحديد الكائن التالي لحمل الاسم الأول واسم العائلة للمستخدم:

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 والإصدارات الأحدث، يمكنك أيضًا الاستعلام عن الأعمدة من جداول متعددة بدون فئة بيانات إضافية عن طريق كتابة طرق الاستعلام التي تُرجع خريطة متعددة.

يمكنك الاطّلاع على المثال من قسم طلب البحث في جداول متعددة. بدلاً من عرض قائمة بمثيلات فئة بيانات مخصّصة تحتفظ إقران مثيلات الـ 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();

أنواع إرجاع خاصة

توفّر الغرفة بعض أنواع الإرجاع الخاصة لدمجها مع واجهة برمجة التطبيقات الأخرى. المكتبات.

طلبات البحث المقسّمة على صفحات باستخدام مكتبة الصفحات

تتوافق الغرفة مع طلبات البحث المقسّمة إلى صفحات من خلال الدمج مع ميزة التقسيم إلى صفحات. المكتبة. في الغرفة 2.3.0-alpha01 أعلى، فيمكن أن تعرض دوال DAO كائنات 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);
}

مصادر إضافية

لمعرفة المزيد من المعلومات عن الوصول إلى البيانات باستخدام أجهزة DAO الخاصة بالغرفة، يُرجى الاطّلاع على المعلومات الإضافية التالية الموارد:

نماذج

الدروس التطبيقية حول الترميز