Android room - 3 一对多关系
Android room - 3 one-to-many relationship
我正在尝试在 3 个表之间创建关系,这些表彼此之间是一对多的顺序。所以 Table1 与 Table 2 具有多对一关系,而 Table2 与 Table3.
具有多对一关系
我想做的是创建一个关系,这样我就可以拥有 Table3 以及相关 Table2 个实体的列表和另一个 Table1 个实体的列表与 Table2 有关。我一直在查看此处的文档和问题,但我尝试过的关系要么给我例外,要么缺少实体,要么提供的实体与我查询的内容无关。
如果我尝试的方法无法做到这一点,您能否指导我朝着正确的方向前进?我目前拥有的是查询第一个关系 (Table3-Table2) 的事务,然后是基于第一个实体 (Table2-Table 的第二个关系1) 并返回所有这些关系的对象。
请让我知道是否已经有 question/blog post 回答这个问题,因为我找不到它。
Link to the simplified table relationships
您必须以分层方式(自下而上)处理此问题
您有一个表 2 (@Embedded
) 的 POJO 和表 3 children (@Relation
)
的列表
然后您有一个 Table1 (@Embedded
) 的 POJO 和一个 Table2 POJO children (@Relation
) 的列表。
例如:-
表1
@Entity(tableName = "table1")
data class Table1(
@PrimaryKey
@ColumnInfo(name = "table1_id")
val id: Long? = null,
@ColumnInfo(name = "table1_name")
val name: String
)
表2
@Entity(
tableName = "table2",
foreignKeys = [
ForeignKey(
entity = Table1::class,
parentColumns = ["table1_id"],
childColumns = ["map_to_parent_in_table1"],
onDelete = CASCADE,
onUpdate = CASCADE
)
]
)
data class Table2(
@PrimaryKey
@ColumnInfo(name = "table2_id")
val id: Long? = null,
@ColumnInfo(name = "map_to_parent_in_table1", index = true)
val map_to_parent: Long,
@ColumnInfo(name = "table2_name")
val name: String
)
表3
@Entity(
tableName = "table3",
foreignKeys = [
ForeignKey(
entity = Table2::class,
parentColumns = ["table2_id"],
childColumns = ["map_to_parent_in_table2"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE
)
]
)
data class Table3(
@PrimaryKey
@ColumnInfo(name = "table3_id")
val id: Long? = null,
@ColumnInfo(name = "map_to_parent_in_table2", index = true)
val map_to_parent: Long,
@ColumnInfo(name = "table3_name")
val name: String
)
foreignKeys
是可选的,但会强制执行并帮助维护参照完整性。在外键中 onDelete
和 onUpdate
是可选的
所以从最低的开始(具有 children 的最小兄弟,即表 2)然后是 POJO
Table2WithTable3Children
data class Table2WithTable3Children(
@Embedded
val table2: Table2,
@Relation(
entity = Table3::class,
parentColumn = "table2_id",
entityColumn = "map_to_parent_in_table2"
)
val children: List<Table3>
)
然后是 POJO
Table1WithTable2ChildrenIncludingTable3Children
data class Table1WithTable2ChildrenIncludingTable3Children(
@Embedded
val table1: Table1,
@Relation(
entity = Table2::class,
parentColumn = "table1_id",
entityColumn = "map_to_parent_in_table1"
)
val children: List<Table2WithTable3Children>
)
因此,如果您获得 Table1WithTable2ChildrenIncludingTable3Children,那么它会包含 Table2WithTable3Children 的列表。
您可以有这样的查询:-
@Query("SELECT * FROM table1" )
@Transaction
abstract fun getAllTable1sWithTable2ChildrenAndTable3Children(): List<Table1WithTable2ChildrenIncludingTable3Children>
这可以像这样使用:-
dao.getAllTable1sWithTable2ChildrenAndTable3Children()
for(t1: Table1WithTable2ChildrenIncludingTable3Children in dao.getAllTable1sWithTable2ChildrenAndTable3Children()) {
Log.d(TAG,"Table1 is ${t1.table1.name} ID is ${t1.table1.id} it has ${t1.children.size} children in Table2 they are:-")
for(t2: Table2WithTable3Children in t1.children) {
Log.d(TAG,"\tTable2 is ${t2.table2.name} ID is ${t2.table2.id} it has ${t2.children} in Table3 they are :-")
for(t3: Table3 in t2.children) {
Log.d(TAG,"\t\tTable3 is ${t3.name} ID is ${t3.id}")
}
}
}
工作Example/Demo
用 @Dao
注释 class AllDao 扩展上面的内容(这包括上面的查询):-
@Dao
abstract class AllDao {
@Insert
abstract fun insert(table1: Table1): Long
@Insert
abstract fun insert(table2: Table2): Long
@Insert
abstract fun insert(table3: Table3): Long
@Query("SELECT * FROM table1" )
@Transaction
abstract fun getAllTable1sWithTable2ChildrenAndTable3Children(): List<Table1WithTable2ChildrenIncludingTable3Children>
}
和一个基本的 @Database
注释 class ThisDatabase :-
@Database(entities = [Table1::class,Table2::class,Table3::class], exportSchema = false, version = 1)
abstract class ThisDatabase: RoomDatabase() {
abstract fun getAllDao(): AllDao
companion object {
private var instance: ThisDatabase? = null
fun getInstance(context: Context): ThisDatabase {
if (instance == null) {
instance = Room.databaseBuilder(context,ThisDatabase::class.java,"this_database.db")
.allowMainThreadQueries()
.build()
}
return instance as ThisDatabase
}
}
}
并全面测试 MainActivity :-
class MainActivity : AppCompatActivity() {
lateinit var db: ThisDatabase
lateinit var dao: AllDao
val TAG = "DBINFO"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = ThisDatabase.getInstance(this)
dao = db.getAllDao()
val t1_1 = dao.insert(Table1( name = "First Table1"))
val t1_2 = dao.insert(Table1(name = "Second Table1"))
val t1_3 = dao.insert(Table1(name = "Third Table1"))
val t2_1 = dao.insert(Table2(name = "First Table2 with First Table1 as Parent", map_to_parent = t1_1))
val t2_2 = dao.insert(Table2(name = "Second Table2 with First Table1 as Parent", map_to_parent = t1_1))
val t2_3 = dao.insert(Table2(name = "Third Table2 with Second Table1 as Parent", map_to_parent = t1_2))
dao.insert(Table3(name = "T31", map_to_parent = t2_1))
dao.insert(Table3(name = "T32", map_to_parent = t2_2))
dao.insert(Table3(name = "T33", map_to_parent = t2_3))
dao.insert(Table3(name = "T34", map_to_parent = t2_1))
dao.insert(Table3(name = "T35", map_to_parent = t2_1))
dao.getAllTable1sWithTable2ChildrenAndTable3Children()
for(t1: Table1WithTable2ChildrenIncludingTable3Children in dao.getAllTable1sWithTable2ChildrenAndTable3Children()) {
Log.d(TAG,"Table1 is ${t1.table1.name} ID is ${t1.table1.id} it has ${t1.children.size} children in Table2 they are:-")
for(t2: Table2WithTable3Children in t1.children) {
Log.d(TAG,"\tTable2 is ${t2.table2.name} ID is ${t2.table2.id} it has ${t2.children.size} in Table3 they are :-")
for(t3: Table3 in t2.children) {
Log.d(TAG,"\t\tTable3 is ${t3.name} ID is ${t3.id}")
}
}
}
}
}
然后当运行第一次写入日志的结果是:-
D/DBINFO: Table1 is First Table1 ID is 1 it has 2 children in Table2 they are:-
D/DBINFO: Table2 is First Table2 with First Table1 as Parent ID is 1 it has 3 in Table3 they are :-
D/DBINFO: Table3 is T31 ID is 1
D/DBINFO: Table3 is T34 ID is 4
D/DBINFO: Table3 is T35 ID is 5
D/DBINFO: Table2 is Second Table2 with First Table1 as Parent ID is 2 it has 1 in Table3 they are :-
D/DBINFO: Table3 is T32 ID is 2
D/DBINFO: Table1 is Second Table1 ID is 2 it has 1 children in Table2 they are:-
D/DBINFO: Table2 is Third Table2 with Second Table1 as Parent ID is 3 it has 1 in Table3 they are :-
D/DBINFO: Table3 is T33 ID is 3
D/DBINFO: Table1 is Third Table1 ID is 3 it has 0 children in Table2 they are:-
我正在尝试在 3 个表之间创建关系,这些表彼此之间是一对多的顺序。所以 Table1 与 Table 2 具有多对一关系,而 Table2 与 Table3.
具有多对一关系我想做的是创建一个关系,这样我就可以拥有 Table3 以及相关 Table2 个实体的列表和另一个 Table1 个实体的列表与 Table2 有关。我一直在查看此处的文档和问题,但我尝试过的关系要么给我例外,要么缺少实体,要么提供的实体与我查询的内容无关。
如果我尝试的方法无法做到这一点,您能否指导我朝着正确的方向前进?我目前拥有的是查询第一个关系 (Table3-Table2) 的事务,然后是基于第一个实体 (Table2-Table 的第二个关系1) 并返回所有这些关系的对象。
请让我知道是否已经有 question/blog post 回答这个问题,因为我找不到它。
Link to the simplified table relationships
您必须以分层方式(自下而上)处理此问题
您有一个表 2 (@Embedded
) 的 POJO 和表 3 children (@Relation
)
然后您有一个 Table1 (@Embedded
) 的 POJO 和一个 Table2 POJO children (@Relation
) 的列表。
例如:-
表1
@Entity(tableName = "table1")
data class Table1(
@PrimaryKey
@ColumnInfo(name = "table1_id")
val id: Long? = null,
@ColumnInfo(name = "table1_name")
val name: String
)
表2
@Entity(
tableName = "table2",
foreignKeys = [
ForeignKey(
entity = Table1::class,
parentColumns = ["table1_id"],
childColumns = ["map_to_parent_in_table1"],
onDelete = CASCADE,
onUpdate = CASCADE
)
]
)
data class Table2(
@PrimaryKey
@ColumnInfo(name = "table2_id")
val id: Long? = null,
@ColumnInfo(name = "map_to_parent_in_table1", index = true)
val map_to_parent: Long,
@ColumnInfo(name = "table2_name")
val name: String
)
表3
@Entity(
tableName = "table3",
foreignKeys = [
ForeignKey(
entity = Table2::class,
parentColumns = ["table2_id"],
childColumns = ["map_to_parent_in_table2"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE
)
]
)
data class Table3(
@PrimaryKey
@ColumnInfo(name = "table3_id")
val id: Long? = null,
@ColumnInfo(name = "map_to_parent_in_table2", index = true)
val map_to_parent: Long,
@ColumnInfo(name = "table3_name")
val name: String
)
foreignKeys
是可选的,但会强制执行并帮助维护参照完整性。在外键中onDelete
和onUpdate
是可选的
所以从最低的开始(具有 children 的最小兄弟,即表 2)然后是 POJO
Table2WithTable3Children
data class Table2WithTable3Children(
@Embedded
val table2: Table2,
@Relation(
entity = Table3::class,
parentColumn = "table2_id",
entityColumn = "map_to_parent_in_table2"
)
val children: List<Table3>
)
然后是 POJO
Table1WithTable2ChildrenIncludingTable3Children
data class Table1WithTable2ChildrenIncludingTable3Children(
@Embedded
val table1: Table1,
@Relation(
entity = Table2::class,
parentColumn = "table1_id",
entityColumn = "map_to_parent_in_table1"
)
val children: List<Table2WithTable3Children>
)
因此,如果您获得 Table1WithTable2ChildrenIncludingTable3Children,那么它会包含 Table2WithTable3Children 的列表。
您可以有这样的查询:-
@Query("SELECT * FROM table1" )
@Transaction
abstract fun getAllTable1sWithTable2ChildrenAndTable3Children(): List<Table1WithTable2ChildrenIncludingTable3Children>
这可以像这样使用:-
dao.getAllTable1sWithTable2ChildrenAndTable3Children()
for(t1: Table1WithTable2ChildrenIncludingTable3Children in dao.getAllTable1sWithTable2ChildrenAndTable3Children()) {
Log.d(TAG,"Table1 is ${t1.table1.name} ID is ${t1.table1.id} it has ${t1.children.size} children in Table2 they are:-")
for(t2: Table2WithTable3Children in t1.children) {
Log.d(TAG,"\tTable2 is ${t2.table2.name} ID is ${t2.table2.id} it has ${t2.children} in Table3 they are :-")
for(t3: Table3 in t2.children) {
Log.d(TAG,"\t\tTable3 is ${t3.name} ID is ${t3.id}")
}
}
}
工作Example/Demo
用 @Dao
注释 class AllDao 扩展上面的内容(这包括上面的查询):-
@Dao
abstract class AllDao {
@Insert
abstract fun insert(table1: Table1): Long
@Insert
abstract fun insert(table2: Table2): Long
@Insert
abstract fun insert(table3: Table3): Long
@Query("SELECT * FROM table1" )
@Transaction
abstract fun getAllTable1sWithTable2ChildrenAndTable3Children(): List<Table1WithTable2ChildrenIncludingTable3Children>
}
和一个基本的 @Database
注释 class ThisDatabase :-
@Database(entities = [Table1::class,Table2::class,Table3::class], exportSchema = false, version = 1)
abstract class ThisDatabase: RoomDatabase() {
abstract fun getAllDao(): AllDao
companion object {
private var instance: ThisDatabase? = null
fun getInstance(context: Context): ThisDatabase {
if (instance == null) {
instance = Room.databaseBuilder(context,ThisDatabase::class.java,"this_database.db")
.allowMainThreadQueries()
.build()
}
return instance as ThisDatabase
}
}
}
并全面测试 MainActivity :-
class MainActivity : AppCompatActivity() {
lateinit var db: ThisDatabase
lateinit var dao: AllDao
val TAG = "DBINFO"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = ThisDatabase.getInstance(this)
dao = db.getAllDao()
val t1_1 = dao.insert(Table1( name = "First Table1"))
val t1_2 = dao.insert(Table1(name = "Second Table1"))
val t1_3 = dao.insert(Table1(name = "Third Table1"))
val t2_1 = dao.insert(Table2(name = "First Table2 with First Table1 as Parent", map_to_parent = t1_1))
val t2_2 = dao.insert(Table2(name = "Second Table2 with First Table1 as Parent", map_to_parent = t1_1))
val t2_3 = dao.insert(Table2(name = "Third Table2 with Second Table1 as Parent", map_to_parent = t1_2))
dao.insert(Table3(name = "T31", map_to_parent = t2_1))
dao.insert(Table3(name = "T32", map_to_parent = t2_2))
dao.insert(Table3(name = "T33", map_to_parent = t2_3))
dao.insert(Table3(name = "T34", map_to_parent = t2_1))
dao.insert(Table3(name = "T35", map_to_parent = t2_1))
dao.getAllTable1sWithTable2ChildrenAndTable3Children()
for(t1: Table1WithTable2ChildrenIncludingTable3Children in dao.getAllTable1sWithTable2ChildrenAndTable3Children()) {
Log.d(TAG,"Table1 is ${t1.table1.name} ID is ${t1.table1.id} it has ${t1.children.size} children in Table2 they are:-")
for(t2: Table2WithTable3Children in t1.children) {
Log.d(TAG,"\tTable2 is ${t2.table2.name} ID is ${t2.table2.id} it has ${t2.children.size} in Table3 they are :-")
for(t3: Table3 in t2.children) {
Log.d(TAG,"\t\tTable3 is ${t3.name} ID is ${t3.id}")
}
}
}
}
}
然后当运行第一次写入日志的结果是:-
D/DBINFO: Table1 is First Table1 ID is 1 it has 2 children in Table2 they are:-
D/DBINFO: Table2 is First Table2 with First Table1 as Parent ID is 1 it has 3 in Table3 they are :-
D/DBINFO: Table3 is T31 ID is 1
D/DBINFO: Table3 is T34 ID is 4
D/DBINFO: Table3 is T35 ID is 5
D/DBINFO: Table2 is Second Table2 with First Table1 as Parent ID is 2 it has 1 in Table3 they are :-
D/DBINFO: Table3 is T32 ID is 2
D/DBINFO: Table1 is Second Table1 ID is 2 it has 1 children in Table2 they are:-
D/DBINFO: Table2 is Third Table2 with Second Table1 as Parent ID is 3 it has 1 in Table3 they are :-
D/DBINFO: Table3 is T33 ID is 3
D/DBINFO: Table1 is Third Table1 ID is 3 it has 0 children in Table2 they are:-