เนื่องจาก SQLite เป็นฐานข้อมูลเชิงสัมพันธ์ คุณจึงกำหนดความสัมพันธ์ระหว่างเอนทิตีได้ แม้ว่าไลบรารีการแมปแบบออบเจ็กต์เชิงสัมพันธ์ส่วนใหญ่จะอนุญาตให้ออบเจ็กต์เอนทิตีอ้างอิงถึงกัน แต่ Room กลับห้ามไม่ให้ทำเช่นนั้นอย่างชัดเจน ดูเหตุผลทางเทคนิคที่อยู่เบื้องหลังการตัดสินใจนี้ได้ที่ทําความเข้าใจสาเหตุที่ Room ไม่อนุญาตให้ใช้การอ้างอิงออบเจ็กต์
ประเภทความสัมพันธ์
ห้องรองรับความสัมพันธ์ประเภทต่อไปนี้
- แบบ 1:1: แสดงความสัมพันธ์ที่เอนทิตตีหนึ่งเกี่ยวข้องกับเอนทิตตีอีกรายการหนึ่ง
- แบบ 1 ต่อหลายรายการ: แสดงความสัมพันธ์ที่เอนทิตีรายการเดียวอาจเกี่ยวข้องกับเอนทิตีประเภทอื่นหลายรายการ
- หลายต่อหลายรายการ: แสดงความสัมพันธ์ที่เอนทิตีดประเภทหนึ่งๆ หลายรายการเชื่อมโยงกับเอนทิตีดประเภทอื่นหลายรายการได้ ซึ่งโดยปกติแล้วต้องใช้ตารางเชื่อม
- ความสัมพันธ์ที่ฝังอยู่ (โดยใช้ออบเจ็กต์ที่ฝัง): แสดงความสัมพันธ์ที่เอนทิตีหนึ่งมีอีกเอนทิตีหนึ่งเป็นฟิลด์ และเอนทิตีที่ฝังอยู่นี้อาจมีเอนทิตีอื่นๆ เพิ่มเติม การดำเนินการนี้ใช้คำอธิบายประกอบ
@Embedded
เลือกระหว่าง 2 แนวทาง
ใน Room การกําหนดและค้นหาความสัมพันธ์ระหว่างเอนทิตีทำได้ 2 วิธี คุณสามารถใช้วิธีใดวิธีหนึ่งต่อไปนี้
- คลาสข้อมูลระดับกลางที่มีออบเจ็กต์ที่ฝังอยู่ หรือ
- เมธอดการค้นหาเชิงสัมพันธ์ที่มีประเภทผลลัพธ์เป็นมัลติแมป
หากคุณไม่มีเหตุผลที่เฉพาะเจาะจงในการใช้คลาสข้อมูลกลาง เราขอแนะนำให้ใช้แนวทางประเภทผลลัพธ์ Multimap ดูข้อมูลเพิ่มเติมเกี่ยวกับแนวทางนี้ได้ที่แสดงผล Multimap
การใช้คลาสข้อมูลระดับกลางช่วยให้คุณไม่ต้องเขียนการค้นหา SQL ที่ซับซ้อน แต่ก็อาจทําให้โค้ดมีความซับซ้อนมากขึ้นเนื่องจากต้องใช้คลาสข้อมูลเพิ่มเติม กล่าวโดยย่อคือ แนวทางประเภทผลลัพธ์ Multimap กำหนดให้คําค้นหา SQL ทํางานมากขึ้น และแนวทางคลาสข้อมูลระดับกลางกําหนดให้โค้ดทํางานมากขึ้น
ใช้แนวทางคลาสข้อมูลระดับกลาง
ในแนวทางคลาสข้อมูลระดับกลาง คุณจะกําหนดคลาสข้อมูลที่จําลองความสัมพันธ์ระหว่างเอนทิตีของห้อง คลาสข้อมูลนี้จะเก็บคู่ระหว่างอินสแตนซ์ของเอนทิตีหนึ่งกับอินสแตนซ์ของเอนทิตีอื่นเป็นออบเจ็กต์ที่ฝัง จากนั้นเมธอดการค้นหาจะแสดงอินสแตนซ์ของคลาสข้อมูลนี้เพื่อใช้ในแอป
ตัวอย่างเช่น คุณสามารถกําหนดคลาสข้อมูล 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 ปี 2019)