การเข้าถึงข้อมูลโดยใช้ DAO ของห้อง

เมื่อคุณใช้ไลบรารีความต่อเนื่องของห้องแชทเพื่อจัดเก็บข้อมูลของแอป คุณจะโต้ตอบ กับข้อมูลที่จัดเก็บไว้โดยการกำหนดออบเจ็กต์การเข้าถึงข้อมูล หรือ DAO แต่ละ DAO รวมวิธีการที่ให้การเข้าถึงฐานข้อมูลของแอปแบบนามธรรม ขณะคอมไพล์ Room จะสร้างการใช้งาน DAO ที่คุณกำหนดโดยอัตโนมัติ

ใช้ DAO เพื่อเข้าถึงฐานข้อมูลของแอปแทนเครื่องมือสร้างคำค้นหาหรือโดยตรง คุณสามารถเก็บการแยก ความกังวลทางสถาปัตยกรรมที่สำคัญ หลัก นอกจากนี้ DAO ยังช่วยให้คุณจำลองการเข้าถึงฐานข้อมูลได้ง่ายขึ้น ทดสอบแอปของคุณ

การวิเคราะห์ DAO

คุณสามารถกำหนด DAO แต่ละรายการเป็นอินเทอร์เฟซหรือคลาสนามธรรมก็ได้ สำหรับขั้นพื้นฐาน กรณีการใช้งาน คุณมักจะใช้อินเทอร์เฟซ ไม่ว่าจะเป็นกรณีใด คุณต้อง เพิ่มคำอธิบายประกอบ DAO ของคุณด้วย @Dao DAO ไม่มีพร็อพเพอร์ตี้ แต่ได้กำหนดวิธีการโต้ตอบอย่างน้อย 1 วิธี กับข้อมูลในฐานข้อมูลของแอป

โค้ดต่อไปนี้เป็นตัวอย่างของ DAO แบบง่ายที่กำหนดเมธอดสำหรับ การแทรก การลบ และเลือกออบเจ็กต์ User รายการในฐานข้อมูลห้อง

KotlinJava
@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 ที่กำหนดการโต้ตอบของฐานข้อมูลอยู่ 2 ประเภท ได้แก่

  • วิธีการที่สะดวกที่ช่วยให้คุณแทรก อัปเดต และลบแถวใน ฐานข้อมูลโดยไม่ต้องเขียนรหัส SQL
  • เมธอดการค้นหาที่ช่วยให้คุณเขียนการค้นหา SQL ของคุณเองเพื่อโต้ตอบกับ ฐานข้อมูล

ส่วนต่อไปนี้จะแสดงวิธีใช้เมธอด DAO ทั้ง 2 ประเภทเพื่อวัตถุประสงค์ต่อไปนี้ กำหนดการโต้ตอบของฐานข้อมูลที่แอปของคุณต้องใช้

วิธีการตามสะดวก

ห้องพักมีคำอธิบายประกอบอำนวยความสะดวกสำหรับระบุวิธีการที่เรียบง่าย การแทรก อัปเดต และการลบโดยที่คุณไม่ต้องเขียนคำสั่ง SQL

ถ้าคุณต้องการระบุส่วนแทรก อัปเดต หรือการลบที่ซับซ้อนขึ้น หรือถ้าต้องการ เพื่อค้นหาข้อมูลในฐานข้อมูล ให้ใช้เมธอดการค้นหาแทน

แทรก

คำอธิบายประกอบ @Insert ช่วยให้คุณ กำหนดวิธีการที่แทรกพารามิเตอร์ลงในตารางที่เหมาะสมใน ฐานข้อมูล โค้ดต่อไปนี้แสดงตัวอย่างเมธอด @Insert ที่ถูกต้องซึ่ง แทรกออบเจ็กต์ User อย่างน้อย 1 รายการในฐานข้อมูล

KotlinJava
@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 ต้องเป็นอินสแตนซ์ของห้องแชท คลาสเอนทิตีข้อมูลมีคำอธิบายประกอบด้วย @Entity หรือคอลเล็กชันของอินสแตนซ์คลาสเอนทิตีข้อมูล โดยที่แต่ละรายการ ชี้ไปยังฐานข้อมูล เมื่อมีการเรียกเมธอด @Insert ห้องแชทจะแทรกแต่ละเมธอด ส่งอินสแตนซ์ของเอนทิตีไปยังตารางฐานข้อมูลที่เกี่ยวข้อง

หากเมธอด @Insert ได้รับพารามิเตอร์เดียว ก็จะแสดง long ได้ ซึ่งเป็น rowId ใหม่สำหรับรายการที่แทรก หากพารามิเตอร์เป็น อาร์เรย์หรือคอลเล็กชัน แล้วแสดงผลอาร์เรย์หรือคอลเล็กชัน แทน long ค่า โดยแต่ละค่าเป็น rowId สำหรับหนึ่งในรายการที่แทรก รายการ ดูข้อมูลเพิ่มเติมเกี่ยวกับการแสดงผลค่า rowId ได้ในข้อมูลอ้างอิง เอกสารประกอบสำหรับ @Insert คำอธิบายประกอบ และเอกสาร SQLite สำหรับ Rowid ตาราง

อัปเดต

คำอธิบายประกอบ @Update ช่วยให้คุณ กำหนดวิธีการที่อัปเดตแถวที่ระบุในตารางฐานข้อมูล ชอบ เมธอด @Insert, เมธอด @Update จะยอมรับอินสแตนซ์เอนทิตีข้อมูลเป็นพารามิเตอร์ โค้ดต่อไปนี้แสดงตัวอย่างของเมธอด @Update ที่พยายามจะ อัปเดตออบเจ็กต์ User อย่างน้อย 1 รายการในฐานข้อมูล:

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

ห้องแชทใช้พารามิเตอร์ คีย์เพื่อจับคู่คำที่ผ่านแล้ว อินสแตนซ์ของเอนทิตีไปยังแถวในฐานข้อมูล หากไม่มีแถวที่มี คีย์หลัก ห้องแชทไม่มีการเปลี่ยนแปลงใดๆ

เมธอด @Update อาจแสดงผลค่า int ที่ระบุตัวเลขหรือไม่ก็ได้ ของแถวที่อัปเดตสำเร็จ

ลบ

คำอธิบายประกอบ @Delete ช่วยให้คุณ กำหนด Method เพื่อลบแถวที่ระบุจากตารางฐานข้อมูล ชอบ เมธอด @Insert, เมธอด @Delete จะยอมรับอินสแตนซ์เอนทิตีข้อมูลเป็นพารามิเตอร์ โค้ดต่อไปนี้แสดงตัวอย่างของเมธอด @Delete ที่พยายามจะ ลบออบเจ็กต์ User อย่างน้อย 1 รายการออกจากฐานข้อมูล:

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

ห้องแชทใช้พารามิเตอร์ คีย์เพื่อจับคู่คำที่ผ่านแล้ว อินสแตนซ์ของเอนทิตีไปยังแถวในฐานข้อมูล หากไม่มีแถวที่มี คีย์หลัก ห้องแชทไม่มีการเปลี่ยนแปลงใดๆ

เมธอด @Delete อาจแสดงผลค่า int ที่ระบุจำนวนของ แถวที่ถูกลบสำเร็จ

วิธีการค้นหา

คำอธิบายประกอบ @Query ช่วยให้คุณ เขียนคำสั่ง SQL และแสดงเป็นเมธอด DAO ใช้วิธีการค้นหาเหล่านี้เพื่อ ค้นหาข้อมูลจากฐานข้อมูลของแอปหรือเมื่อต้องการดำเนินการที่ซับซ้อนมากขึ้น การแทรก อัปเดต และการลบ

Room จะตรวจสอบการค้นหา SQL ในเวลาคอมไพล์ ซึ่งหมายความว่าหากมีปัญหา พร้อมกับการค้นหา ข้อผิดพลาดของการคอมไพล์จะเกิดขึ้นแทนที่รันไทม์ล้มเหลว

คำค้นหาแบบง่าย

โค้ดต่อไปนี้ระบุเมธอดที่ใช้คำค้นหา SELECT แบบง่ายเพื่อแสดงผล ออบเจ็กต์ User ทั้งหมดในฐานข้อมูล:

KotlinJava
@Query("SELECT * FROM user")
fun loadAllUsers(): Array<User>
@Query("SELECT * FROM user")
public User[] loadAllUsers();

ส่วนต่อไปนี้จะแสดงวิธีแก้ไขตัวอย่างนี้สำหรับการใช้งานโดยทั่วไป กรณี

แสดงผลชุดย่อยของคอลัมน์ในตาราง

ส่วนใหญ่แล้ว คุณจะแสดงเพียงชุดย่อยของคอลัมน์จากตาราง ที่คุณกำลังสอบถาม ตัวอย่างเช่น UI อาจแสดงแค่ นามสกุลของผู้ใช้ ไม่ใช่รายละเอียดทั้งหมดเกี่ยวกับผู้ใช้รายนั้น เพื่อบันทึก ทรัพยากรและลดความซับซ้อนของการดำเนินการค้นหา ให้ค้นหาเฉพาะ ฟิลด์ที่คุณต้องการ

Room ช่วยให้คุณส่งคืนออบเจ็กต์ง่ายๆ จากคำค้นหาใดก็ได้ คุณสามารถจับคู่ชุดคอลัมน์ผลลัพธ์กับออบเจ็กต์ที่แสดงผล ตัวอย่างเช่น คุณสามารถ สามารถกำหนดออบเจ็กต์ต่อไปนี้เพื่อเก็บชื่อและนามสกุลของผู้ใช้

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

จากนั้นคุณจะส่งคืนออบเจ็กต์ง่ายๆ นั้นจากวิธีการค้นหาได้ โดยทำดังนี้

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

ห้องแชทเข้าใจว่าการค้นหาแสดงผลค่าสำหรับ first_name และ last_name คอลัมน์ และสามารถนำค่าเหล่านี้มาแมปกับช่องใน NameTuple ชั้นเรียน หากข้อความค้นหาแสดงคอลัมน์ที่ไม่ได้จับคู่กับฟิลด์ ในวัตถุที่ส่งคืน ห้องจะแสดงคำเตือน

ส่งต่อพารามิเตอร์พื้นฐานไปยังการค้นหา

ส่วนใหญ่แล้ว เมธอด DAO จะต้องยอมรับพารามิเตอร์เพื่อให้สามารถ ดำเนินการกรอง ห้องแชทรองรับการใช้พารามิเตอร์เมธอดเป็นการเชื่อมโยง ในข้อความค้นหาของคุณ

ตัวอย่างเช่น โค้ดต่อไปนี้กำหนดเมธอดที่จะแสดงผลผู้ใช้ทั้งหมด ที่มีอายุมากกว่าเกณฑ์ที่กำหนด:

KotlinJava
@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);

คุณยังส่งผ่านพารามิเตอร์หลายรายการหรืออ้างอิงพารามิเตอร์เดียวกันหลายรายการได้ด้วย จำนวนครั้งในข้อความค้นหา ดังที่แสดงในโค้ดต่อไปนี้:

KotlinJava
@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 ของคุณอาจกำหนดให้คุณต้องส่งผ่านจำนวนตัวแปร พารามิเตอร์ที่ไม่รู้จักจนถึงรันไทม์ ห้องแชทจะเข้าใจเมื่อพารามิเตอร์ แสดงคอลเล็กชันและขยายโดยอัตโนมัติที่รันไทม์ตาม จำนวนพารามิเตอร์ที่ระบุ

ตัวอย่างเช่น โค้ดต่อไปนี้จะระบุเมธอดที่แสดงข้อมูลเกี่ยวกับ ผู้ใช้ทั้งหมดจากภูมิภาคย่อยๆ ดังนี้

KotlinJava
@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 เพื่ออ้างอิงอักขระมากกว่า 1 ตาราง

โค้ดต่อไปนี้จะกำหนดเมธอดที่รวม 3 ตารางเข้าด้วยกันเพื่อแสดงผล หนังสือที่ยืมไว้ให้ผู้ใช้รายหนึ่งในปัจจุบัน:

KotlinJava
@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);

นอกจากนี้คุณยังกำหนดออบเจ็กต์ง่ายๆ เพื่อแสดงชุดย่อยของคอลัมน์จากหลายรายการได้ ตารางที่เข้าร่วม ตามที่อธิบายไว้ใน ส่งคืนข้อมูลบางส่วนของตาราง คอลัมน์ โค้ดต่อไปนี้กำหนด DAO ด้วยเมธอดที่ แสดงชื่อผู้ใช้และชื่อหนังสือที่ยืม:

KotlinJava
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 ขึ้นไป คุณสามารถค้นหาคอลัมน์จากหลายตารางได้โดยไม่ต้อง การกำหนดคลาสข้อมูลเพิ่มเติมโดยการเขียนวิธีการค้นหาที่ส่งคืน multimap

ลองดูตัวอย่างจากส่วนสืบค้นข้อมูลหลายตาราง แทนที่จะส่งคืนรายการของอินสแตนซ์ของคลาสข้อมูลที่กำหนดเองที่เก็บไว้ การจับคู่อินสแตนซ์ User และ Book คุณจะแสดงผลการแมปของ User และ Book โดยตรงจากวิธีข้อความค้นหาของคุณ:

KotlinJava
@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() เพื่อแสดงผลผู้ใช้ที่มีหนังสือ 3 เล่มขึ้นไปเท่านั้น เช็คเอาต์:

KotlinJava
@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();

หากไม่ต้องการแมปวัตถุทั้งหมด คุณแสดงการจับคู่ระหว่าง คอลัมน์ที่เฉพาะเจาะจงใน Query ของคุณโดยการตั้งค่า keyColumn และ แอตทริบิวต์ของ valueColumn ในคำอธิบายประกอบ @MapInfo ใน วิธีการค้นหา:

KotlinJava
@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();

ประเภทการแสดงผลพิเศษ

ห้องพักมีประเภทผลลัพธ์พิเศษสำหรับการผสานรวมกับ API อื่นๆ ห้องสมุด

การค้นหาที่ใส่เลขหน้าด้วยไลบรารีการสร้างหน้า

Room รองรับการค้นหาที่ใส่เลขหน้าผ่านการผสานรวมกับ การแบ่งหน้า คลัง ในห้อง 2.3.0-alpha01 และ ที่สูงขึ้น DAO สามารถแสดงผล PagingSource ออบเจ็กต์สำหรับการใช้งาน กับหน้า 3

KotlinJava
@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 ตามที่แสดงในตัวอย่างต่อไปนี้

KotlinJava
@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 ของห้องได้จากหัวข้อเพิ่มเติมต่อไปนี้ แหล่งข้อมูล:

ตัวอย่าง

Codelab

  • ห้อง Android ที่มีมุมมอง (Java) (Kotlin)