Selama menggunakan library persistensi Room untuk menyimpan data aplikasi, Anda berinteraksi dengan data yang disimpan dengan menentukan objek akses data, atau DAO. Setiap DAO menyertakan metode yang menawarkan akses abstrak ke database aplikasi Anda. Pada waktu kompilasi, Room otomatis akan membuat implementasi DAO yang Anda tentukan.
Dengan menggunakan DAO untuk mengakses database aplikasi, bukan builder kueri atau kueri langsung, Anda dapat mempertahankan pemisahan fokus yang merupakan prinsip penting dalam arsitektur. DAO juga memudahkan Anda meniru akses database saat menguji aplikasi.
Anatomi DAO
Anda dapat menentukan setiap DAO sebagai antarmuka atau class abstrak. Untuk kasus
penggunaan dasar, biasanya Anda menggunakan antarmuka. Dalam kedua kasus tersebut, Anda harus selalu
menganotasi DAO dengan @Dao
. DAO
tidak memiliki properti, tetapi menentukan satu atau beberapa metode untuk berinteraksi
dengan data di database aplikasi Anda.
Kode berikut adalah contoh DAO sederhana yang menentukan metode untuk
menyisipkan, menghapus, dan memilih objek User
dalam database 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(); }
Ada dua jenis metode DAO yang menentukan interaksi database:
- Metode praktis yang memungkinkan Anda menyisipkan, memperbarui, dan menghapus baris di database tanpa harus menulis kode SQL.
- Metode kueri yang memungkinkan untuk menulis kueri SQL Anda sendiri untuk berinteraksi dengan database.
Bagian berikut menunjukkan cara menggunakan kedua jenis metode DAO untuk menentukan interaksi database yang diperlukan aplikasi.
Metode praktis
Room menyediakan anotasi praktis untuk menentukan metode yang menjalankan penyisipan, pembaruan, dan penghapusan sederhana tanpa mengharuskan Anda menulis pernyataan SQL.
Jika Anda harus menentukan penyisipan, pembaruan, atau penghapusan yang lebih kompleks, atau jika Anda perlu membuat kueri data dalam database, gunakan metode kueri.
Menyisipkan
Anotasi @Insert
memungkinkan Anda
menentukan metode yang menyisipkan parameternya ke dalam tabel yang sesuai di
database. Kode berikut menunjukkan contoh metode @Insert
yang valid
yang menyisipkan satu atau beberapa objek User
ke dalam database:
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); }
Setiap parameter untuk metode @Insert
harus berupa instance class
entity data Room yang dianotasikan dengan
@Entity
atau kumpulan instance class entity data, yang masing-masing
mengarah ke database. Saat metode @Insert
dipanggil, Room akan menyisipkan setiap
instance entity yang diteruskan ke tabel database yang bersangkutan.
Jika metode @Insert
menerima satu parameter, metode ini dapat menampilkan nilai long
,
yang merupakan rowId
baru untuk item yang disisipkan. Jika parameter adalah
array atau kumpulan, tampilkan array atau kumpulan
nilai long
sebagai gantinya, dengan setiap nilai sebagai rowId
untuk salah satu item
yang disisipkan. Untuk mempelajari lebih lanjut cara menampilkan nilai rowId
, lihat dokumentasi
referensi untuk anotasi @Insert
dan Dokumentasi SQLite untuk tabel
rowid.
Update
Anotasi @Update
memungkinkan Anda
menentukan metode yang memperbarui baris tertentu dalam tabel database. Seperti
metode @Insert
, metode @Update
menerima instance entity data sebagai parameter.
Kode berikut menunjukkan contoh metode @Update
yang mencoba
memperbarui satu atau beberapa objek User
di database:
Kotlin
@Dao interface UserDao { @Update fun updateUsers(vararg users: User) }
Java
@Dao public interface UserDao { @Update public void updateUsers(User... users); }
Room menggunakan kunci utama untuk mencocokkan instance entity yang diteruskan ke baris dalam database. Jika tidak ada baris dengan kunci utama yang sama, Room tidak akan membuat perubahan.
Metode @Update
secara opsional dapat menampilkan nilai int
yang menunjukkan jumlah
baris yang berhasil diperbarui.
Menghapus
Anotasi @Delete
memungkinkan Anda
menentukan metode yang menghapus baris tertentu dari tabel database. Seperti
metode @Insert
, metode @Delete
menerima instance entity data sebagai parameter.
Kode berikut menunjukkan contoh metode @Delete
yang mencoba
menghapus satu atau beberapa objek User
dari database:
Kotlin
@Dao interface UserDao { @Delete fun deleteUsers(vararg users: User) }
Java
@Dao public interface UserDao { @Delete public void deleteUsers(User... users); }
Room menggunakan kunci utama untuk mencocokkan instance entity yang diteruskan ke baris dalam database. Jika tidak ada baris dengan kunci utama yang sama, Room tidak akan membuat perubahan.
Metode @Delete
secara opsional dapat menampilkan nilai int
yang menunjukkan jumlah
baris yang berhasil dihapus.
Metode kueri
Anotasi @Query
memungkinkan Anda
menulis pernyataan SQL dan menampilkannya sebagai metode DAO. Gunakan metode kueri ini untuk
mengueri data dari database aplikasi, atau ketika perlu melakukan penyisipan, pembaruan, dan penghapusan yang
lebih kompleks.
Room memvalidasi kueri SQL pada waktu kompilasi. Ini artinya bahwa akan terjadi error kompilasi, bukan kegagalan runtime, jika ada masalah dengan kueri Anda.
Kueri sederhana
Kode berikut menentukan metode yang menggunakan kueri SELECT
sederhana untuk menampilkan
semua objek User
dalam database:
Kotlin
@Query("SELECT * FROM user") fun loadAllUsers(): Array<User>
Java
@Query("SELECT * FROM user") public User[] loadAllUsers();
Bagian berikut menunjukkan cara memodifikasi contoh ini untuk kasus penggunaan umum.
Menampilkan subset kolom tabel
Biasanya, Anda hanya perlu menampilkan subkumpulan kolom dari tabel yang sedang dikueri. Misalnya, UI Anda mungkin hanya menampilkan nama depan dan nama belakang pengguna, bukan setiap detail pengguna tersebut. Untuk menghemat resource dan menyederhanakan eksekusi kueri, cukup buat kueri kolom yang Anda butuhkan.
Dengan Room, Anda dapat menampilkan objek sederhana dari kueri mana pun selama Anda dapat memetakan kumpulan kolom hasil ke objek yang ditampilkan. Misalnya, Anda dapat menentukan objek berikut untuk menyimpan nama depan dan nama belakang pengguna:
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; }
Kemudian, Anda dapat menampilkan objek sederhana tersebut dari metode kueri:
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();
Room memahami bahwa kueri tersebut menampilkan nilai untuk kolom first_name
dan
last_name
, serta bahwa nilai ini dapat dipetakan ke dalam kolom class
NameTuple
. Jika kueri menampilkan kolom yang tidak dipetakan ke kolom
dalam objek yang ditampilkan, Room akan menampilkan peringatan.
Meneruskan parameter sederhana ke kueri
Sering kali, metode DAO harus menerima parameter agar dapat menjalankan operasi pemfilteran. Room mendukung penggunaan parameter metode sebagai parameter binding di kueri Anda.
Misalnya, kode berikut menentukan metode yang menampilkan semua pengguna di atas usia tertentu:
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);
Anda juga dapat meneruskan beberapa parameter atau mereferensikan parameter yang sama beberapa kali dalam kueri, seperti yang ditunjukkan pada kode berikut:
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);
Meneruskan kumpulan parameter ke kueri
Beberapa metode DAO mungkin mengharuskan Anda meneruskan parameter dengan jumlah bervariasi yang tidak diketahui hingga runtime. Room dapat mengetahui saat suatu parameter merepresentasikan sebuah kumpulan, dan akan otomatis memperluasnya saat runtime berdasarkan jumlah parameter yang diberikan.
Misalnya, kode berikut menentukan metode yang menampilkan informasi tentang semua pengguna dari subset region:
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);
Membuat kueri beberapa tabel
Beberapa kueri mungkin memerlukan akses ke beberapa tabel untuk menghitung
hasilnya. Anda dapat menggunakan klausa JOIN
dalam kueri SQL untuk mereferensikan lebih
dari satu tabel.
Kode berikut menentukan metode yang menggabungkan tiga tabel untuk menampilkan buku yang saat ini dipinjamkan kepada pengguna tertentu:
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);
Anda juga dapat menentukan objek sederhana untuk menampilkan subset kolom dari beberapa tabel gabungan seperti yang dibahas di bagian Menampilkan subset kolom tabel. Kode berikut menentukan DAO dengan metode yang menampilkan nama pengguna dan nama buku yang telah dipinjam:
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; } }
Menampilkan multimap
Di Room 2.4 dan lebih tinggi, Anda juga dapat membuat kueri kolom dari beberapa tabel tanpa menentukan class data tambahan dengan menulis metode kueri yang menampilkan multimap.
Pertimbangkan contoh dari bagian Membuat kueri beberapa tabel.
Daripada menampilkan daftar instance dari class data kustom yang menyimpan
pasangan instance User
dan Book
, Anda dapat menampilkan pemetaan User
dan
Book
secara langsung dari metode kueri Anda:
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();
Saat metode kueri menampilkan multimap, Anda dapat menulis kueri yang menggunakan
klausa GROUP BY
agar dapat memanfaatkan kemampuan SQL untuk
penghitungan dan pemfilteran lanjutan. Misalnya, Anda dapat memodifikasi metode
loadUserAndBookNames()
untuk hanya menampilkan pengguna yang meminjam tiga buku
atau lebih:
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();
Jika tidak perlu memetakan keseluruhan objek, Anda juga dapat menampilkan pemetaan antara
kolom tertentu dalam kueri dengan menetapkan
keyColumn
dan
valueColumn
dalam
anotasi @MapInfo
pada
metode kueri Anda:
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();
Jenis nilai yang ditampilkan khusus
Room menyediakan beberapa jenis nilai yang ditampilkan khusus untuk integrasi dengan library API lainnya.
Kueri yang dipaginasi dengan library Paging
Room mendukung kueri yang dipaginasi melalui integrasi dengan library
Paging. Di Room 2.3.0-alpha01 dan
yang lebih tinggi, DAO dapat menampilkan
objek PagingSource
untuk digunakan
dengan Paging 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); }
Untuk informasi selengkapnya tentang memilih parameter jenis untuk PagingSource
, lihat
Memilih jenis kunci
dan nilai.
Akses kursor langsung
Jika logika aplikasi memerlukan akses langsung ke baris hasil, Anda dapat menulis
metode DAO untuk menampilkan objek Cursor
seperti yang ditunjukkan pada contoh berikut:
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); }
Referensi lainnya
Untuk mempelajari lebih lanjut cara mengakses data menggunakan DAO Room, lihat referensi tambahan berikut.