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

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

วิดีโอ

บล็อก