เลือกประเภทความสัมพันธ์ระหว่างออบเจ็กต์

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

วิดีโอ

บล็อก