【问题标题】:Android room - 3 one-to-many relationshipAndroid 房间 - 3 一对多的关系
【发布时间】:2022-01-24 17:12:14
【问题描述】:

我正在尝试在 3 个彼此按顺序一对多的表之间创建关系。所以表 1 与表 2 是多对一的,而表 2 与表 3 是多对一的。

我要做的是创建一个关系,这样我就可以拥有 Table3 以及相关的 Table2 实体列表以及与 Table2 相关的另一个 Table1 实体列表。我一直在查看此处的文档和问题,但我尝试过的关系要么给了我例外,要么缺少实体,要么提供了与我查询的内容无关的实体。

如果按照我尝试的方式无法做到这一点,您能否指导我朝着正确的方向前进?我目前拥有的是一个事务,它查询第一个关系(Table3-Table2),然后根据第一个实体(Table2-Table1)查询第二个关系,并返回所有这些关系的对象。

如果已经有问题/博客文章回答了这个问题,请告诉我,因为我找不到它。

Link to the simplified table relationships

【问题讨论】:

    标签: android android-room one-to-many


    【解决方案1】:

    您必须以分层方式(自下而上)处理此问题

    您有一个用于 Table2 的 POJO (@Embedded),其中包含一个 Table3 子级列表 (@Relation)

    然后,您将拥有 Table1 (@Embedded) 的 POJO,其中包含 Table2 POJO 子项 (@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
    )
    

    Table3

    @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 是可选的,但可以强制执行并帮助维护参照完整性。在外键中,onDeleteonUpdate 是可选的

    所以从最低的(有孩子的最小的兄弟姐妹,即 Table2)开始,然后是 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}")
                }
            }
        }
    

    工作示例/演示

    使用@Dao 注释类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 注释类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}")
                    }
                }
            }
        }
    }
    

    那么第一次运行时写入日志的Result是:-

    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:-
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-04-17
      • 1970-01-01
      • 1970-01-01
      • 2021-12-19
      • 1970-01-01
      • 1970-01-01
      • 2019-07-28
      相关资源
      最近更新 更多