Do SQLite là một cơ sở dữ liệu quan hệ, nên bạn có thể xác định mối quan hệ giữa các thực thể. Tuy nhiên, trong khi hầu hết các thư viện ánh xạ quan hệ đối tượng cho phép các đối tượng thực thể tham chiếu lẫn nhau thì Room cấm điều này một cách rõ ràng. Để tìm hiểu lý do kỹ thuật đằng sau quyết định này, hãy xem phần Tìm hiểu lý do Room không cho phép tham chiếu đối tượng.
Các loại mối quan hệ
Room hỗ trợ các loại mối quan hệ sau:
- Một với một: Biểu thị mối quan hệ trong đó một thực thể liên quan đến một thực thể khác.
- Một với nhiều: Biểu thị mối quan hệ trong đó một thực thể có thể liên quan đến nhiều thực thể thuộc một loại khác.
- Nhiều với nhiều: Biểu thị mối quan hệ trong đó nhiều thực thể thuộc một loại có thể liên quan đến nhiều thực thể thuộc một loại khác. Việc này thường yêu cầu một bảng liên kết.
- Mối quan hệ lồng nhau (sử dụng đối tượng nhúng): Biểu thị một mối quan hệ trong đó một thực thể chứa một thực thể khác dưới dạng trường và thực thể lồng nhau này có thể chứa các thực thể khác. Thao tác này sử dụng chú thích
@Embedded
.
Chọn một trong hai phương pháp
Trong Room, có hai cách để xác định và truy vấn mối quan hệ giữa các thực thể. Bạn có thể sử dụng:
- Lớp dữ liệu trung gian có các đối tượng được nhúng hoặc
- Phương thức truy vấn quan hệ với kiểu dữ liệu trả về nhiều bản đồ.
Nếu không có lý do cụ thể để sử dụng lớp dữ liệu trung gian, bạn nên sử dụng phương pháp sử dụng kiểu dữ liệu trả về đa ánh xạ. Để tìm hiểu thêm về phương pháp này, hãy xem phần Trả về cấu trúc đa ánh xạ.
Phương pháp lớp dữ liệu trung gian giúp bạn không phải viết các truy vấn SQL phức tạp, nhưng cũng có thể làm tăng tính phức tạp của mã vì phương pháp này yêu cầu các lớp dữ liệu bổ sung. Tóm lại, phương pháp kiểu dữ liệu trả về nhiều bản đồ đòi hỏi các truy vấn SQL làm nhiều việc hơn; còn phương pháp lớp dữ liệu trung gian sẽ yêu cầu mã làm nhiều việc hơn.
Sử dụng phương pháp lớp dữ liệu trung gian
Trong cách tiếp cận lớp dữ liệu trung gian, bạn xác định một lớp dữ liệu giúp mô hình hoá mối quan hệ giữa các thực thể Room của bạn. Lớp dữ liệu này duy trì ghép nối giữa các bản sao của một thực thể và các bản sao của một thực thể khác dưới dạng đối tượng được nhúng. Sau đó, phương thức truy vấn có thể trả về các bản sao của lớp dữ liệu này để sử dụng trong ứng dụng.
Ví dụ: bạn có thể xác định lớp dữ liệu UserBook
để biểu diễn người dùng thư viện với cuốn sách cụ thể được cho mượn và xác định phương thức truy vấn để truy xuất danh sách các thực thể UserBook
từ cơ sở dữ liệu:
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;
}
Sử dụng phương pháp sử dụng kiểu dữ liệu trả về nhiều bản đồ
Trong phương pháp tiếp cận loại dữ liệu trả về nhiều bản đồ, bạn không cần phải xác định thêm lớp dữ liệu nào cả. Thay vào đó, bạn xác định loại dữ liệu trả về nhiều bản đồ cho phương thức dựa trên cấu trúc bản đồ bạn muốn và trực tiếp xác định mối quan hệ giữa các thực thể trong truy vấn SQL.
Ví dụ: phương thức truy vấn sau đây trả về mối liên kết của các thực thể User
và Book
để biểu diễn người dùng thư viện với cuốn sách cụ thể được cho mượn:
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();
Tạo đối tượng nhúng
Đôi khi, bạn muốn biểu thị một thực thể hoặc đối tượng dữ liệu dưới dạng một tổng thể ràng buộc trong logic cơ sở dữ liệu, ngay cả khi đối tượng đó chứa nhiều trường. Trong các trường hợp này, bạn có thể sử dụng chú giải @Embedded
để biểu thị một đối tượng bạn muốn phân rã vào các trường con trong bảng. Sau đó, bạn có thể truy vấn các trường nhúng giống như với các cột riêng lẻ khác.
Ví dụ: lớp User
có thể gồm một trường thuộc loại Address
đại diện cho thành phần (composition) của các trường có tên street
, city
, state
và postCode
. Để lưu trữ các cột đã được phân rã riêng rẽ trong bảng, hãy thêm trường Address
. Lớp này sẽ xuất hiện trong lớp User
được chú thích bằng @Embedded
. Đoạn mã sau đây minh hoạ điều này:
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;
}
Khi này, bảng biểu diễn đối tượng User
chứa các cột có tên như sau: id
, firstName
, street
, state
, city
và post_code
.
Nếu một thực thể có nhiều trường nhúng cùng loại, thì bạn có thể khiến mỗi cột là duy nhất bằng cách đặt thuộc tính prefix
. Sau đó, Room sẽ thêm giá trị được cung cấp vào đầu tên mỗi cột trong đối tượng nhúng.
Tài nguyên khác
Để tìm hiểu thêm về việc xác định mối quan hệ giữa các thực thể trong Room, xem xét các tài nguyên khác dưới đây.
Video
- Tính năng mới trong Room (Hội nghị Nhà phát triển Android 2019)