هنگامی که از کتابخانه ماندگاری اتاق برای ذخیره داده های برنامه خود استفاده می کنید، با تعریف اشیاء دسترسی به داده یا DAO با داده های ذخیره شده تعامل دارید. هر DAO شامل روش هایی است که دسترسی انتزاعی به پایگاه داده برنامه شما را ارائه می دهد. در زمان کامپایل، Room به طور خودکار پیاده سازی های DAO هایی را که شما تعریف کرده اید تولید می کند.
با استفاده از DAO برای دسترسی به پایگاه داده برنامه خود به جای سازندگان پرس و جو یا پرس و جوهای مستقیم، می توانید جداسازی نگرانی ها را که یک اصل مهم معماری است، حفظ کنید. DAO ها همچنین هنگام آزمایش برنامه خود دسترسی به پایگاه داده را برای شما آسان تر می کنند.
آناتومی یک DAO
شما می توانید هر DAO را به عنوان یک رابط یا یک کلاس انتزاعی تعریف کنید. برای موارد استفاده اولیه، معمولاً از یک رابط استفاده می کنید. در هر صورت، همیشه باید DAO های خود را با @Dao
حاشیه نویسی کنید. DAO ها ویژگی ندارند، اما یک یا چند روش را برای تعامل با داده های پایگاه داده برنامه شما تعریف می کنند.
کد زیر نمونه ای از یک DAO ساده است که روش هایی را برای درج، حذف و انتخاب اشیاء User
در پایگاه داده اتاق تعریف می کند:
کاتلین
@Dao interface UserDao { @Insert fun insertAll(vararg users: User) @Delete fun delete(user: User) @Query("SELECT * FROM user") fun getAll(): List<User> }
جاوا
@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 را برای تعریف تعاملات پایگاه دادهای که برنامه شما به آن نیاز دارد نشان میدهد.
روش های راحتی
Room حاشیه نویسی های راحتی را برای تعریف روش هایی ارائه می دهد که درج، به روز رسانی و حذف ساده را بدون نیاز به نوشتن دستور SQL انجام می دهند.
اگر نیاز به تعریف درجها، بهروزرسانیها یا حذفهای پیچیدهتری دارید، یا اگر نیاز به پرسوجویی از دادهها در پایگاه داده دارید، به جای آن از روش پرس و جو استفاده کنید.
درج کنید
حاشیهنویسی @Insert
به شما امکان میدهد روشهایی را تعریف کنید که پارامترهای خود را در جدول مناسب در پایگاه داده وارد میکنند. کد زیر نمونه هایی از روش های @Insert
معتبر را نشان می دهد که یک یا چند شیء User
را در پایگاه داده وارد می کنند:
کاتلین
@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>) }
جاوا
@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
باید یا نمونهای از یک کلاس موجودیت داده Room باشد که با @Entity
حاشیهنویسی شده است یا مجموعهای از نمونههای کلاس موجودیت داده که هر کدام به یک پایگاه داده اشاره میکنند. هنگامی که یک متد @Insert
فراخوانی می شود، Room هر نمونه موجودیت ارسال شده را در جدول پایگاه داده مربوطه درج می کند.
اگر متد @Insert
یک پارامتر واحد دریافت کند، میتواند مقدار long
را برگرداند که همان rowId
جدید آیتم درج شده است. اگر پارامتر یک آرایه یا مجموعه است، در عوض یک آرایه یا مجموعه ای از مقادیر long
را با هر مقدار به عنوان rowId
برای یکی از موارد درج شده برگردانید. برای کسب اطلاعات بیشتر در مورد بازگرداندن مقادیر rowId
، به مستندات مرجع برای حاشیهنویسی @Insert
و مستندات SQLite برای جداول ردیف مراجعه کنید.
به روز رسانی
حاشیه نویسی @Update
به شما امکان می دهد روش هایی را تعریف کنید که ردیف های خاصی را در جدول پایگاه داده به روز می کنند. مانند روشهای @Insert
، روشهای @Update
نمونههای موجودیت داده را به عنوان پارامتر میپذیرند. کد زیر نمونهای از یک روش @Update
را نشان میدهد که تلاش میکند یک یا چند شیء User
را در پایگاه داده بهروزرسانی کند:
کاتلین
@Dao interface UserDao { @Update fun updateUsers(vararg users: User) }
جاوا
@Dao public interface UserDao { @Update public void updateUsers(User... users); }
Room از کلید اصلی برای تطبیق نمونههای موجودیت تصویب شده با ردیفهای پایگاه داده استفاده میکند. اگر ردیفی با همان کلید اصلی وجود نداشته باشد، Room هیچ تغییری ایجاد نمی کند.
یک متد @Update
میتواند بهصورت اختیاری مقدار int
را برگرداند که نشاندهنده تعداد ردیفهایی است که با موفقیت بهروزرسانی شدهاند.
حذف کنید
حاشیه نویسی @Delete
به شما امکان می دهد روش هایی را تعریف کنید که ردیف های خاصی را از جدول پایگاه داده حذف می کند. مانند روش های @Insert
، روش های @Delete
نمونه های موجودیت داده را به عنوان پارامتر می پذیرند. کد زیر نمونهای از روش @Delete
را نشان میدهد که تلاش میکند یک یا چند شیء User
را از پایگاه داده حذف کند:
کاتلین
@Dao interface UserDao { @Delete fun deleteUsers(vararg users: User) }
جاوا
@Dao public interface UserDao { @Delete public void deleteUsers(User... users); }
Room از کلید اصلی برای تطبیق نمونههای موجودیت تصویب شده با ردیفهای پایگاه داده استفاده میکند. اگر ردیفی با همان کلید اصلی وجود نداشته باشد، Room هیچ تغییری ایجاد نمی کند.
یک متد @Delete
میتواند به صورت اختیاری یک مقدار int
را برگرداند که نشاندهنده تعداد ردیفهایی است که با موفقیت حذف شدهاند.
روش های پرس و جو
حاشیه نویسی @Query
به شما امکان می دهد عبارات SQL را بنویسید و آنها را به عنوان روش های DAO در معرض دید قرار دهید. از این روشهای جستجو برای جستجوی دادهها از پایگاه داده برنامه خود یا زمانی که نیاز به درج، بهروزرسانی و حذف پیچیدهتر دارید، استفاده کنید.
اتاق درخواستهای SQL را در زمان کامپایل تأیید میکند. این بدان معناست که اگر در پرس و جو شما مشکلی وجود داشته باشد، به جای شکست در زمان اجرا، یک خطای کامپایل رخ می دهد.
پرس و جوهای ساده
کد زیر متدی را تعریف می کند که از یک کوئری ساده SELECT
برای برگرداندن تمام اشیاء User
در پایگاه داده استفاده می کند:
کاتلین
@Query("SELECT * FROM user") fun loadAllUsers(): Array<User>
جاوا
@Query("SELECT * FROM user") public User[] loadAllUsers();
بخشهای زیر نحوه اصلاح این مثال را برای موارد استفاده معمولی نشان میدهد.
زیر مجموعه ای از ستون های جدول را برگردانید
بیشتر اوقات، شما فقط نیاز دارید که زیرمجموعه ای از ستون ها را از جدولی که پرس و جو می کنید برگردانید. به عنوان مثال، UI شما ممکن است به جای تمام جزئیات مربوط به آن کاربر، فقط نام و نام خانوادگی یک کاربر را نمایش دهد. برای صرفه جویی در منابع و ساده سازی اجرای پرس و جو، فقط فیلدهایی را که نیاز دارید پرس و جو کنید.
Room به شما امکان می دهد یک شی ساده را از هر یک از پرس و جوهای خود بازگردانید تا زمانی که بتوانید مجموعه ستون های نتیجه را بر روی شی برگشتی نگاشت کنید. به عنوان مثال، می توانید شی زیر را برای نگه داشتن نام و نام خانوادگی یک کاربر تعریف کنید:
کاتلین
data class NameTuple( @ColumnInfo(name = "first_name") val firstName: String?, @ColumnInfo(name = "last_name") val lastName: String? )
جاوا
public class NameTuple { @ColumnInfo(name = "first_name") public String firstName; @ColumnInfo(name = "last_name") @NonNull public String lastName; }
سپس، می توانید آن شی ساده را از متد query خود برگردانید:
کاتلین
@Query("SELECT first_name, last_name FROM user") fun loadFullName(): List<NameTuple>
جاوا
@Query("SELECT first_name, last_name FROM user") public List<NameTuple> loadFullName();
Room می داند که پرس و جو مقادیری را برای ستون های first_name
و last_name
برمی گرداند و این مقادیر را می توان در فیلدهای کلاس NameTuple
نگاشت. اگر پرس و جو ستونی را برمی گرداند که روی فیلدی در شیء برگشتی نگاشت نمی شود، Room یک هشدار نمایش می دهد.
پارامترهای ساده را به یک پرس و جو منتقل کنید
اغلب اوقات، متدهای DAO شما نیاز به پذیرش پارامترها دارند تا بتوانند عملیات فیلتر کردن را انجام دهند. اتاق از استفاده از پارامترهای متد به عنوان پارامترهای bind در جستارهای شما پشتیبانی می کند.
به عنوان مثال، کد زیر متدی را تعریف می کند که همه کاربران بالای یک سن خاص را برمی گرداند:
کاتلین
@Query("SELECT * FROM user WHERE age > :minAge") fun loadAllUsersOlderThan(minAge: Int): Array<User>
جاوا
@Query("SELECT * FROM user WHERE age > :minAge") public User[] loadAllUsersOlderThan(int minAge);
همانطور که در کد زیر نشان داده شده است، همچنین می توانید چندین پارامتر را ارسال کنید یا به یک پارامتر چندین بار در یک کوئری ارجاع دهید:
کاتلین
@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>
جاوا
@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 شما ممکن است از شما نیاز داشته باشند که تعداد متغیری از پارامترها را ارسال کنید که تا زمان اجرا مشخص نیست. اتاق متوجه می شود که یک پارامتر چه زمانی یک مجموعه را نشان می دهد و به طور خودکار آن را در زمان اجرا بر اساس تعداد پارامترهای ارائه شده گسترش می دهد.
به عنوان مثال، کد زیر روشی را تعریف می کند که اطلاعات مربوط به همه کاربران را از زیر مجموعه ای از مناطق برمی گرداند:
کاتلین
@Query("SELECT * FROM user WHERE region IN (:regions)") fun loadUsersFromRegions(regions: List<String>): List<User>
جاوا
@Query("SELECT * FROM user WHERE region IN (:regions)") public List<User> loadUsersFromRegions(List<String> regions);
پرس و جو از چندین جدول
ممکن است برخی از پرس و جوهای شما برای محاسبه نتیجه نیاز به دسترسی به چندین جدول داشته باشند. شما می توانید از بندهای JOIN
در جستارهای SQL خود برای ارجاع به بیش از یک جدول استفاده کنید.
کد زیر روشی را تعریف میکند که سه جدول را به یکدیگر متصل میکند تا کتابهایی را که در حال حاضر امانت دارند به یک کاربر خاص برگرداند:
کاتلین
@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>
جاوا
@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);
همچنین میتوانید اشیاء ساده را برای برگرداندن زیرمجموعهای از ستونها از چندین جدول متصل تعریف کنید، همانطور که در بخش Return a subset of a tables ستونها بحث شد. کد زیر یک 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>> // You can also define this class in a separate file. data class UserBook(val userName: String?, val bookName: String?) }
جاوا
@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 و بالاتر، میتوانید با نوشتن روشهای پرس و جو که یک نقشه چندگانه را برمیگردانند، ستونها را از چندین جدول بدون تعریف کلاس داده اضافی جستجو کنید.
مثالی را از بخش Query multiple tables در نظر بگیرید. به جای بازگرداندن فهرستی از نمونههای یک کلاس داده سفارشی که جفتهایی از نمونههای User
و Book
را در خود نگه میدارد، میتوانید نگاشت User
و Book
مستقیماً از روش جستجوی خود برگردانید:
کاتلین
@Query( "SELECT * FROM user" + "JOIN book ON user.id = book.user_id" ) fun loadUserAndBookNames(): Map<User, List<Book>>
جاوا
@Query( "SELECT * FROM user" + "JOIN book ON user.id = book.user_id" ) public Map<User, List<Book>> loadUserAndBookNames();
هنگامی که روش پرس و جو شما یک نقشه چندگانه برمی گرداند، می توانید پرس و جوهایی بنویسید که از بندهای GROUP BY
استفاده می کنند و به شما امکان می دهند از قابلیت های SQL برای محاسبات و فیلترهای پیشرفته استفاده کنید. برای مثال، میتوانید روش loadUserAndBookNames()
خود را طوری تغییر دهید که فقط کاربرانی را که سه یا چند کتاب بررسی کردهاند بازگرداند:
کاتلین
@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>>
جاوا
@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
در روش درخواست خود، نگاشتها را بین ستونهای خاص در جستجوی خود برگردانید:
کاتلین
@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>>
جاوا
@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();
انواع برگشت ویژه
Room انواع خاصی از بازگشت را برای ادغام با سایر کتابخانه های API فراهم می کند.
پرس و جوهای صفحه بندی شده با کتابخانه Paging
اتاق از پرس و جوهای صفحه بندی شده از طریق ادغام با کتابخانه Paging پشتیبانی می کند. در Room 2.3.0-alpha01 و بالاتر، DAO ها می توانند اشیاء PagingSource
را برای استفاده با Paging 3 برگردانند.
کاتلین
@Dao interface UserDao { @Query("SELECT * FROM users WHERE label LIKE :query") fun pagingSource(query: String): PagingSource<Int, User> }
جاوا
@Dao interface UserDao { @Query("SELECT * FROM users WHERE label LIKE :query") PagingSource<Integer, User> pagingSource(String query); }
برای اطلاعات بیشتر در مورد انتخاب پارامترهای نوع برای PagingSource
، به انتخاب انواع کلید و مقدار مراجعه کنید.
دسترسی مستقیم به مکان نما
اگر منطق برنامه شما نیاز به دسترسی مستقیم به ردیفهای برگشتی دارد، میتوانید روشهای DAO خود را برای برگرداندن یک شی Cursor
بنویسید، همانطور که در مثال زیر نشان داده شده است:
کاتلین
@Dao interface UserDao { @Query("SELECT * FROM user WHERE age > :minAge LIMIT 5") fun loadRawUsersOlderThan(minAge: Int): Cursor }
جاوا
@Dao public interface UserDao { @Query("SELECT * FROM user WHERE age > :minAge LIMIT 5") public Cursor loadRawUsersOlderThan(int minAge); }
منابع اضافی
برای کسب اطلاعات بیشتر در مورد دسترسی به داده ها با استفاده از اتاق DAO، به منابع اضافی زیر مراجعه کنید: