เนื่องจาก SQLite เป็นฐานข้อมูลเชิงสัมพันธ์ คุณจึงกำหนดความสัมพันธ์ระหว่างเอนทิตีได้ แต่ในขณะที่ไลบรารีการแมปออบเจ็กต์เชิงสัมพันธ์ส่วนใหญ่จะอนุญาตให้ออบเจ็กต์เอนทิตีอ้างอิงถึงกันได้ แต่ Room จะไม่อนุญาตอย่างชัดเจน หากต้องการดูเหตุผลทางเทคนิค เบื้องหลังการตัดสินใจนี้ โปรดดูทำความเข้าใจเหตุผลที่ Room ไม่อนุญาตการอ้างอิงออบเจ็กต์
ประเภทความสัมพันธ์
Room รองรับความสัมพันธ์ประเภทต่อไปนี้
- แบบหนึ่งต่อหนึ่ง: แสดงถึงความสัมพันธ์ที่เอนทิตีเดียวมีความสัมพันธ์กับเอนทิตีเดียวอีกรายการ
- แบบหนึ่งต่อหลาย: แสดงถึงความสัมพันธ์ที่เอนทิตีเดียวมีความสัมพันธ์กับเอนทิตีหลายรายการของอีกประเภทได้
- แบบหลายต่อหลาย: แสดงถึงความสัมพันธ์ที่เอนทิตีหลายรายการของ ประเภทหนึ่งมีความสัมพันธ์กับเอนทิตีหลายรายการของอีกประเภทได้ ซึ่งมักจะต้องใช้ตารางเชื่อม
- ความสัมพันธ์แบบซ้อนโดยใช้ออบเจ็กต์ที่ฝัง: แสดงถึง
ความสัมพันธ์ที่เอนทิตีหนึ่งมีเอนทิตีอื่นเป็นพร็อพเพอร์ตี้ และ
เอนทิตีที่ซ้อนนี้อาจมีเอนทิตีอื่นๆ เพิ่มเติมได้ ซึ่งใช้คำอธิบายประกอบ
@Embedded
เลือกระหว่าง 2 วิธี
ใน Room คุณสามารถกำหนดและค้นหาความสัมพันธ์ระหว่างเอนทิตีได้ 2 วิธี โดยสามารถใช้วิธีใดวิธีหนึ่งต่อไปนี้
- คลาสข้อมูลระดับกลางที่มีออบเจ็กต์ที่ฝัง หรือ
- ฟังก์ชันการค้นหาเชิงสัมพันธ์ที่มีประเภทการแสดงผลเป็น multimap
หากไม่มีเหตุผลเฉพาะที่จะใช้คลาสข้อมูลระดับกลาง เราขอแนะนำให้ใช้วิธีประเภทการแสดงผลเป็น multimap ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีนี้ได้ที่ แสดงผล multimap
วิธีคลาสข้อมูลระดับกลางช่วยให้คุณไม่ต้องเขียนการค้นหา SQL ที่ซับซ้อน แต่ก็อาจทำให้โค้ดซับซ้อนมากขึ้นเนื่องจากต้องใช้คลาสข้อมูลเพิ่มเติม กล่าวโดยย่อคือ วิธีประเภทการแสดงผลเป็น multimap กำหนดให้การค้นหา SQL ของคุณทำงานมากขึ้น และวิธีคลาสข้อมูลระดับกลางกำหนดให้โค้ดของคุณทำงานมากขึ้น
ใช้วิธีคลาสข้อมูลระดับกลาง
ในวิธีคลาสข้อมูลระดับกลาง คุณจะกำหนดคลาสข้อมูลที่จำลองความสัมพันธ์ระหว่างเอนทิตี Room คลาสข้อมูลนี้จะเก็บการจับคู่ ระหว่างอินสแตนซ์ของเอนทิตีหนึ่งกับอินสแตนซ์ของเอนทิตีอื่นเป็น ออบเจ็กต์ที่ฝัง จากนั้นฟังก์ชันการค้นหาจะแสดงผลอินสแตนซ์ของคลาสข้อมูลนี้เพื่อใช้ในแอปได้
ตัวอย่างเช่น คุณสามารถกำหนดคลาสข้อมูล UserBook เพื่อแสดงผู้ใช้ห้องสมุดที่ยืมหนังสือเฉพาะ และกำหนดฟังก์ชันการค้นหาเพื่อดึงข้อมูลรายการอินสแตนซ์ UserBook จากฐานข้อมูลได้ดังนี้
@Dao interface UserBookDao { @Query( """ SELECT user.name AS userName, book.name AS bookName FROM user JOIN book ON user.id = book.user_id """ ) fun loadUserAndBookNames(): LiveData<List<UserBook>> } data class UserBook(val userName: String, val bookName: String)
ใช้วิธีประเภทการแสดงผลเป็น multimap
ในวิธีประเภทการแสดงผลเป็น multimap คุณไม่จำเป็นต้องกำหนดคลาสข้อมูลเพิ่มเติม แต่คุณจะกำหนดประเภทการแสดงผลเป็น multimap สำหรับ ฟังก์ชันตามโครงสร้างแผนที่ที่ต้องการ และกำหนด ความสัมพันธ์ระหว่างเอนทิตีโดยตรงในการค้นหา SQL
ตัวอย่างเช่น ฟังก์ชันการค้นหาต่อไปนี้จะแสดงผลการแมปอินสแตนซ์ User และ Book เพื่อแสดงผู้ใช้ห้องสมุดที่ยืมหนังสือเฉพาะ
@Query( """ SELECT * FROM user JOIN book ON user.id = book.user_id """ ) suspend fun loadUserAndBookNames(): Map<User, List<Book>>
นอกจากนี้ คุณยังค้นหาความสัมพันธ์แบบหนึ่งต่อหนึ่งที่ไม่มีเอนทิตีอื่นเกี่ยวข้องได้ด้วยประเภทการแสดงผลเป็น multimap ฟังก์ชันการค้นหาต่อไปนี้จะแสดงผลการแมป
User และจำนวนหนังสือที่ผู้ใช้ยืมโดยใช้
@MapColumn คำอธิบายประกอบ:
@Query( """ SELECT user.*, COUNT(book.id) AS book_count FROM user LEFT JOIN book ON user.id = book.user_id GROUP BY user.id """ ) suspend fun loadUserAndBookCount(): Map<User, @MapColumn(columnName = "book_count") Int>
สร้างออบเจ็กต์ที่ฝัง
บางครั้งคุณอาจต้องการแสดงเอนทิตีหรือออบเจ็กต์ข้อมูลเป็นหน่วยเดียวที่สอดคล้องกันในตรรกะฐานข้อมูล แม้ว่าออบเจ็กต์จะมีพร็อพเพอร์ตี้หลายรายการก็ตาม ในกรณีเช่นนี้
ให้ใช้คำอธิบายประกอบ @Embedded เพื่อแยกออบเจ็กต์ออกเป็น
พร็อพเพอร์ตี้ย่อยภายในตาราง จากนั้นคุณจะค้นหาพร็อพเพอร์ตี้ที่ฝังได้เช่นเดียวกับคอลัมน์อื่นๆ
ตัวอย่างเช่น คลาส User อาจมีพร็อพเพอร์ตี้ Address ที่แสดงถึงการรวมพร็อพเพอร์ตี้ street, city, state และ postCode หากต้องการจัดเก็บคอลัมน์ที่รวมไว้แยกกันในตาราง ให้ใส่คำอธิบายประกอบ @Embedded ในพร็อพเพอร์ตี้ Address ในคลาส User ข้อมูลโค้ดต่อไปนี้แสดงการตั้งค่านี้
data class Address( val street: String?, val state: String?, val city: String?, @ColumnInfo(name = "post_code") val postCode: Int ) @Entity data class User( @PrimaryKey val id: Int, val firstName: String, @Embedded val address: Address? )
จากนั้นตารางที่แสดงออบเจ็กต์ User จะมีคอลัมน์ที่มีชื่อต่อไปนี้ id, firstName, street, state, city และ post_code
หากเอนทิตีมีพร็อพเพอร์ตี้ที่ฝังหลายรายการที่มีประเภทเดียวกัน คุณสามารถทำให้
แต่ละคอลัมน์ไม่ซ้ำกันได้โดยการตั้งค่าพร็อพเพอร์ตี้ prefix จากนั้น Room จะเพิ่มค่าที่ระบุไว้ที่จุดเริ่มต้นของชื่อคอลัมน์แต่ละคอลัมน์ในออบเจ็กต์ที่ฝัง