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

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

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

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

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

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

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

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

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

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

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

แทรก

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

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 สำหรับ Rowid ตาราง

อัปเดต

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

Kotlin

@Dao
interface UserDao {
    @Update
    fun updateUsers(vararg users: User)
}

Java

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

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

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

ลบ

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

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 ใช้วิธีการค้นหาเหล่านี้เพื่อ ค้นหาข้อมูลจากฐานข้อมูลของแอปหรือเมื่อต้องการดำเนินการที่ซับซ้อนมากขึ้น การแทรก อัปเดต และการลบ

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

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

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

Kotlin

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

Java

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

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

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

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

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

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

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

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

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

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

หากไม่ต้องการแมปวัตถุทั้งหมด คุณแสดงการจับคู่ระหว่าง คอลัมน์ที่เฉพาะเจาะจงใน Query ของคุณโดยการตั้งค่า 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();

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

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

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

Room รองรับการค้นหาที่ใส่เลขหน้าผ่านการผสานรวมกับ การแบ่งหน้า คลัง ในห้อง 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 ของห้องได้จากหัวข้อเพิ่มเติมต่อไปนี้ แหล่งข้อมูล:

ตัวอย่าง

Codelab

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