本文翻譯自官網(wǎng)
使用Room進(jìn)行持久化存儲(chǔ)---綜述
通過 Room entities 定義數(shù)據(jù) ---Room 系列(1)
Android 中使用 Room 實(shí)踐
我們可以使用 DAO (data access object 數(shù)據(jù)訪問對(duì)象) 來訪問數(shù)據(jù)。 一系列的 Dao 對(duì)象組成了 Room 的主要部分。每個(gè) DAO 對(duì)象包含了訪問應(yīng)用中數(shù)據(jù)庫(kù)的方法。
我們?cè)谑褂玫臅r(shí)候,可以將DAO 定義為一個(gè)接口或者抽象類。如果是抽象類,它可以選擇帶有且僅有一個(gè) RoomDatabase 參數(shù)的構(gòu)造函數(shù)。我們無需自己實(shí)現(xiàn)DAO , Room 將在編譯時(shí)創(chuàng)建這個(gè) DAO 的實(shí)現(xiàn)。
需要注意的是,Room 不支持在主線程中訪問數(shù)據(jù)庫(kù),除非在構(gòu)建的時(shí)候調(diào)用了 allowMainThreadQueries() 方法。因?yàn)樵谒膶⑹欠浅:臅r(shí)的。
定義方法
你可以在 DAO 類中,使用很多方便的數(shù)據(jù)庫(kù)操作。
Insert
當(dāng)我們創(chuàng)建一個(gè)以 @Insert 注解的 DAO 方法的時(shí)候,Room 將在一個(gè)事務(wù)中產(chǎn)生一個(gè)插入它所有參數(shù)到數(shù)據(jù)庫(kù)實(shí)現(xiàn)
@Dao
public interface MyDao {
@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 方法僅僅接收一個(gè)參數(shù),它可以訪問一個(gè)long 類型數(shù)據(jù),代表了插入項(xiàng)的 rowId。以此類推,如果參數(shù)是一個(gè)數(shù)組或者集合,返回的將是 long [] 后者 List<Long>.
Update
Update 用以通過指定參數(shù)修改 entity 。
它首先會(huì)根據(jù) entity 的主鍵匹配數(shù)據(jù),然后修改對(duì)應(yīng)行的數(shù)據(jù)。
@Dao
public interface MyDao {
@Update
public void updateUsers(User... users);
}
當(dāng)然,你也可以讓這些方法返回一個(gè) int 值,代表更新的行號(hào)。
Delete
Delete 代表著從數(shù)據(jù)庫(kù)中刪除一系列的 entity(譯注:一個(gè)entity對(duì)應(yīng)著數(shù)據(jù)庫(kù)table中一個(gè)數(shù)據(jù)行)。它將使用主鍵找到那些需要被刪除的 entity。
@Dao
public interface MyDao {
@Delete
public void deleteUsers(User... users);
}
Query
@Query 是 DAO 類中的主要注解。它允許在數(shù)據(jù)庫(kù)中執(zhí)行讀寫操作。
查詢操作在編譯的時(shí)候就已經(jīng)確定了,如果這個(gè)查詢是有問題的,將會(huì)發(fā)生編譯錯(cuò)誤而不用等待運(yùn)行時(shí)報(bào)錯(cuò)。
Room 也檢查了查詢操作的返回值。如果返回對(duì)象的成員和相應(yīng)的 列 名不匹配,Room 將通過下面兩種方式給出警告:
- 給出一個(gè)相關(guān)成員不匹配的的警告
- 給出一個(gè) error
簡(jiǎn)單的查詢操作
@Dao
public interface MyDao {
@Query("SELECT * FROM user")
public User[] loadAllUsers();
}
上述是一個(gè)非常簡(jiǎn)單的查詢操作,將得到所有的 User 。在編譯的時(shí)候,Room 就知道它是查詢所有 user 表中的列,所以如果包含一些語法錯(cuò)誤,亦或者 user 并不存在,Room 顯示報(bào)錯(cuò)信息。
在查詢語句中添加參數(shù)
常常我們的查詢都是帶參數(shù)的,以進(jìn)行數(shù)據(jù)過濾,比如說只找到那些年齡大于某個(gè)數(shù)值的用戶。
@Dao
public interface MyDao {
@Query("SELECT * FROM user WHERE age > :minAge")
public User[] loadAllUsersOlderThan(int minAge);
}
在進(jìn)行編譯處理的時(shí)候,Room 會(huì)將方法中的 minAge 和 :minAge 進(jìn)行匹配設(shè)置。同樣,如果無法匹配(譯注:比如方法中不帶參數(shù),但是上面的查詢語句中卻帶有參數(shù)),就是顯示錯(cuò)誤信息。
當(dāng)然,你也可以傳遞多個(gè)參數(shù):
@Dao
public interface MyDao {
@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);
}
返回某些列
很多時(shí)候,我們只需要一個(gè) entity(一個(gè)數(shù)據(jù)行) 中的某些列。舉例而言,在 UI 中,你可能只需要展示用戶的姓和名,而不是關(guān)于用戶的所有信息。只查詢必要的信息,查詢完成的速度會(huì)更快。
Room 允許從查詢中返回一個(gè) Java 對(duì)象,只要這些列可以被映射為一個(gè)對(duì)象。舉例而言,你可以創(chuàng)建一個(gè)下面的 Java 對(duì)象僅僅獲取用戶的姓和名:
public class NameTuple {
@ColumnInfo(name="first_name")
public String firstName;
@ColumnInfo(name="last_name")
public String lastName;
}
現(xiàn)在,可以在查詢方法中返回這個(gè) POJO :
@Dao
public interface MyDao {
@Query("SELECT first_name, last_name FROM user")
public List<NameTuple> loadFullName();
}
Room 可以感知到返回的 first_name 和 last_name 列中的值可以被映射到 NameTuple 類中的屬性中。如果返回的太多列,或者返回的列中 NameTuple 類中并不存在這個(gè)屬性,Room 會(huì)給出警告。
傳遞一個(gè)集合參數(shù)
有些查詢操作可能需要傳遞的參數(shù)的個(gè)數(shù)是不確定的,只有在運(yùn)行的時(shí)候才知道具體的數(shù)量。舉個(gè)栗子,現(xiàn)在我們需要檢索出某幾個(gè)區(qū)域的用戶信息:
@Dao
public interface MyDao {
@Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)")
public List<NameTuple> loadUsersFromRegions(List<String> regions);
}