เนื่องจาก SQLite เป็นฐานข้อมูลเชิงสัมพันธ์ คุณจึงกำหนดความสัมพันธ์ระหว่างเอนทิตีได้ แต่ในขณะที่ไลบรารีการแมปออบเจ็กต์เชิงสัมพันธ์ส่วนใหญ่จะอนุญาตให้ออบเจ็กต์เอนทิตีอ้างอิงถึงกันได้ แต่ Room จะไม่อนุญาตอย่างชัดเจน หากต้องการดูเหตุผลทางเทคนิคเบื้องหลังการตัดสินใจนี้ โปรดดูทำความเข้าใจเหตุผลที่ Room ไม่อนุญาตการอ้างอิงออบเจ็กต์
ประเภทความสัมพันธ์
Room รองรับความสัมพันธ์ประเภทต่อไปนี้
- แบบหนึ่งต่อหนึ่ง: แสดงถึงความสัมพันธ์ที่เอนทิตีเดียวมีความสัมพันธ์กับเอนทิตีเดียวอีกเอนทิตีหนึ่ง
- แบบหนึ่งต่อหลาย: แสดงถึงความสัมพันธ์ที่เอนทิตีเดียวมีความสัมพันธ์กับเอนทิตีหลายรายการของอีกประเภทหนึ่งได้
- แบบหลายต่อหลาย: แสดงถึงความสัมพันธ์ที่เอนทิตีหลายรายการของ ประเภทหนึ่งมีความสัมพันธ์กับเอนทิตีหลายรายการของอีกประเภทหนึ่งได้ ซึ่งโดยปกติแล้วจะต้องใช้ตารางเชื่อม
- ความสัมพันธ์แบบซ้อน (โดยใช้ออบเจ็กต์ที่ฝัง): แสดงถึง
ความสัมพันธ์ที่เอนทิตีหนึ่งมีเอนทิตีอื่นเป็นฟิลด์ และเอนทิตีที่
ซ้อนกันนี้อาจมีเอนทิตีอื่นๆ เพิ่มเติมได้ ซึ่งใช้คำอธิบายประกอบ
@Embedded
เลือกระหว่าง 2 วิธี
ใน Room คุณสามารถกำหนดและค้นหาความสัมพันธ์ระหว่างเอนทิตีได้ 2 วิธี โดยคุณสามารถใช้วิธีใดวิธีหนึ่งต่อไปนี้
- คลาสข้อมูลระดับกลางที่มีออบเจ็กต์ที่ฝัง หรือ
- เมธอดการค้นหาเชิงสัมพันธ์ที่มีประเภทการแสดงผลเป็น multimap
หากไม่มีเหตุผลเฉพาะเจาะจงในการใช้คลาสข้อมูลระดับกลาง เราขอแนะนำให้ใช้วิธีประเภทการแสดงผลเป็น multimap ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีนี้ได้ที่ แสดงผล multimap
วิธีคลาสข้อมูลระดับกลางช่วยให้คุณไม่ต้องเขียนคําค้นหา SQL ที่ซับซ้อน แต่ก็อาจทําให้โค้ดซับซ้อนมากขึ้นด้วยเนื่องจากต้องใช้คลาสข้อมูลเพิ่มเติม กล่าวโดยสรุปคือ วิธีประเภทการแสดงผลเป็น multimap กําหนดให้คําค้นหา SQL ของคุณทํางานมากขึ้น และวิธีคลาสข้อมูลระดับกลางกําหนดให้โค้ดของคุณทํางานมากขึ้น
ใช้วิธีคลาสข้อมูลระดับกลาง
ในวิธีคลาสข้อมูลระดับกลาง คุณจะกำหนดคลาสข้อมูลที่จำลองความสัมพันธ์ระหว่างเอนทิตี Room คลาสข้อมูลนี้จะเก็บการจับคู่ระหว่างอินสแตนซ์ของเอนทิตีหนึ่งกับอินสแตนซ์ของเอนทิตีอื่นเป็น ออบเจ็กต์ที่ฝัง จากนั้นเมธอดการค้นหาจะแสดงผลอินสแตนซ์ของคลาสข้อมูลนี้เพื่อใช้ในแอปได้
ตัวอย่างเช่น คุณสามารถกำหนดคลาสข้อมูล UserBook เพื่อแสดงถึงผู้ใช้ห้องสมุดที่ยืมหนังสือบางเล่ม และกำหนดเมธอดการค้นหาเพื่อดึงข้อมูลรายการอินสแตนซ์ UserBook จากฐานข้อมูลได้ดังนี้
Kotlin
@Dao
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>>
}
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();
}
public class UserBook {
public String userName;
public String bookName;
}
ใช้วิธีประเภทการแสดงผลเป็น multimap
ในวิธีประเภทการแสดงผลเป็น multimap คุณไม่จำเป็นต้องกำหนดคลาสข้อมูลเพิ่มเติม แต่คุณจะกำหนดประเภทการแสดงผลเป็น multimap สำหรับ เมธอดตามโครงสร้างแผนที่ที่ต้องการ และกำหนดความสัมพันธ์ ระหว่างเอนทิตีในคําค้นหา SQL โดยตรง
ตัวอย่างเช่น เมธอดการค้นหาต่อไปนี้จะแสดงผลการแมปอินสแตนซ์ 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();
สร้างออบเจ็กต์ที่ฝัง
บางครั้งคุณอาจต้องการแสดงเอนทิตีหรือออบเจ็กต์ข้อมูลเป็นหน่วยที่สอดคล้องกันในตรรกะฐานข้อมูล แม้ว่าออบเจ็กต์จะมีหลายฟิลด์ก็ตาม ในกรณีเช่นนี้ คุณสามารถใช้คำอธิบายประกอบ @Embedded เพื่อแสดงออบเจ็กต์
ที่ต้องการแยกย่อยเป็นฟิลด์ย่อยภายในตาราง จากนั้นคุณจะค้นหาฟิลด์ที่ฝังได้เช่นเดียวกับคอลัมน์อื่นๆ
ตัวอย่างเช่น คลาส User อาจมีฟิลด์ประเภท Address ซึ่งแสดงถึงการรวมฟิลด์ที่ชื่อ street, city, state และ postCode หากต้องการจัดเก็บคอลัมน์ที่รวมไว้แยกกันในตาราง ให้ใส่ฟิลด์ Address ซึ่งควรปรากฏในคลาส User ที่มีคำอธิบายประกอบ @Embedded ข้อมูลโค้ดต่อไปนี้แสดงให้เห็นถึงลักษณะดังกล่าว
Kotlin
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?
)
Java
public class Address {
public String street;
public String state;
public String city;
@ColumnInfo(name = "post_code") public int postCode;
}
@Entity
public class User {
@PrimaryKey public int id;
public String firstName;
@Embedded public Address address;
}
จากนั้นตารางที่แสดงออบเจ็กต์ User จะมีคอลัมน์ที่มีชื่อต่อไปนี้ id, firstName, street, state, city และ post_code
หากเอนทิตีมีฟิลด์ที่ฝังหลายรายการที่มีประเภทเดียวกัน คุณสามารถทำให้แต่ละ
คอลัมน์ไม่ซ้ำกันได้โดยการตั้งค่าprefix พร็อพเพอร์ตี้ จากนั้น Room จะเพิ่มค่าที่ระบุไว้ที่จุดเริ่มต้นของชื่อคอลัมน์แต่ละคอลัมน์ในออบเจ็กต์ที่ฝัง
แหล่งข้อมูลเพิ่มเติม
ดูข้อมูลเพิ่มเติมเกี่ยวกับการกำหนดความสัมพันธ์ระหว่างเอนทิตีใน Room ได้จากแหล่งข้อมูลเพิ่มเติมต่อไปนี้
วิดีโอ
- มีอะไรใหม่ใน Room (Android Dev Summit '19)