给出的答案将嵌入式类型更改为外键类型,我不是要找这个。
我有一个学生桌和一个嵌入式类型地址。
学生模式
+----+------+------------+
| id | name | address_id |
+----+------+------------+
| 1 | John | 1 |
| 2 | Jane | 2 |
+----+------+------------+
地址架构
+----+------------------+
| id | addressLine |
+----+------------------+
| 1 | 123 Acme Street |
| 2 | 456 Beach Street |
+----+------------------+
学生实体
@Entity(tableName = "student")
data class Student(
@PrimaryKey var id: Long,
var name: String?,
@Embedded var address: Address // can't change, given answer changed it
)
地址实体
@Entity(tableName = "address")
data class Address(
@PrimaryKey var id: Long,
val addressLine: String
)
DAO界面
@Dao
interface StudentDao {
@Query("SELECT * FROM student WHERE id = :id INNER JOIN address ON student.address_id = address.id")
fun findById(id: Long): Student
}
问题:当前无法填充学生的嵌入式地址。
答案 0 :(得分:0)
用例的常用方法是使用额外的POJO类(不是实体)从两个表中获取联接结果。
因此,实体:
@Entity(tableName = "student")
data class Student(
@PrimaryKey var id: Long,
var name: String?,
var address_id: Long // <- you can make it foreign key in addition
)
@Entity(tableName = "address")
data class Address(
@PrimaryKey var id: Long,
val addressLine: String
)
和辅助POJO类:
data class StudentWithAdress( // <-- you can change the class name to more descriptive one
@Embedded var student: Student
@Embedded var address: Address
)
那你的道:
@Dao
interface StudentDao {
@Query("SELECT * FROM student WHERE id = :id INNER JOIN address ON student.address_id = address.id")
fun findById(id: Long): StudentWithAdress
}
已更新
第二种方法是使用one-to-one Room's @Relation而不是SQLite联接
此方法使用相同实体,但查询类和辅助类稍有不同:
data class StudentWithAdress(
@Embedded var student: Student
@Relation(
parentColumn = "addressId",
entityColumn = "id"
)
var address: Address
)
查询会更简单:
@Transaction
@Query("SELECT * FROM student WHERE id = :id")
fun findById(id: Long): StudentWithAdress
}
结论
Student
类应包含 ONLY addressId
(不是整个Address
对象),并且您使用单独的类StudentWithAdress
1}}和Student
。因此,要将值插入Address
,您应该在相应的Student
表中插入addressId
。这是常见且正确的方法。Address
内容保存在Address
实体中),但是我认为这违反了关系表规范化的原理,我不希望将此内容包含在我的答案中,因为它是反模式。更新2(反模式)
我不建议这样做,但是如果您坚持可以使用下一个模式:
Stident
它如何工作? @Embedded表示实际上Sqlite表@Entity(tableName = "address")
data class Address(
@PrimaryKey var idAddress: Long, // <-- changed
val addressLine: String
)
@Entity(tableName = "student")
data class Student(
@PrimaryKey var id: Long,
var name: String?,
@Embedded var address: Address
)
包含Student
的所有字段。在您的实际Sqlite表中,您将有4列-id,name,idAddress,addressLine(这就是为什么必须更改Address
主键名称的原因,因为不能存在具有相同名称的字段)。
Room将其隐藏了一点,您可以通过Address
字段使用Student
对象。为什么这不好?让我们看一下场景:
address
的ID = 1,addressLine =“某些地址#1”。Address
对象中设置了该地址,并将其保留。在Student
表中的Sqlite的内部将保存值Student
,id = 1
。addressLine = Some address #1
中的addressLine
更改为“某些地址#2”。Address
表中仍然有Student
的旧值。那是一个错误。或者您应该在addressLine
表上保留此更改,这也很糟糕。