【问题标题】:I don't know why Room is not inserting all the data in tables 1 - N我不知道为什么 Room 没有在表 1 - N 中插入所有数据
【发布时间】:2021-10-22 16:51:14
【问题描述】:

请有人帮助我!我在做一个小项目,我有这个功能:

private fun getRoutePoints(routeId: String) {
        val dbReference = FirebaseDatabase.getInstance().getReference("/routes/$routeId")
        val listOfPoints: MutableList<PointOfInterest> = mutableListOf()
        dbReference.child("pointsOfInterest").get().addOnSuccessListener { pointsArray ->
            pointsArray.children.forEach { point ->
                val dataMap = point.value as Map<*, *>
                val routeIdToInsert = routeId.toInt()
                val id = point.key!!.toInt()
                val pointOfInterest = PointOfInterest(
                    id = id,
                    title = dataMap["title"].toString(),
                    description = dataMap["description"].toString(),
                    latitude = dataMap["latitude"].toString().toDouble(),
                    longitude = dataMap["longitude"].toString().toDouble(),
                    imageUrl = dataMap["imageUrl"].toString(),
                    routeId = routeIdToInsert
                )
                listOfPoints.add(id, pointOfInterest)
                if (pointsArray.children.count() == listOfPoints.size) {
                    CoroutineScope(Dispatchers.IO).launch {
                        AppDatabase.getInstance(application).routeDao.insertRoutePoints(listOfPoints)
                    }
                }
            }
        }
    }

当第二次插入完成时出现,执行再次返回到 for each,就像所有子级都没有被循环一样

我的 DAO 课程

>     @Dao interface RouteDao {
>     @Insert(onConflict = IGNORE)
>     suspend fun insertRoute(route: Route)
> 
>     @Query("SELECT * FROM routes_tbl")
>     fun getAllRoutes(): List<Route>
> 
>  
> 
>    @Transaction
>     @Insert
>     fun insertRoutePoints(points: List<PointOfInterest>) }

我的实体: 我的路线实体:

> @Entity(tableName = "routes_tbl") data class Route(
>     @PrimaryKey(autoGenerate = false) val id: Int,
>     @ColumnInfo(name = "title") val title: String,
>     @ColumnInfo(name = "description") val description: String,
>     @ColumnInfo(name = "historic_period") val historicPeriod: String,
>     @ColumnInfo(name = "image_url") val imageUrl: String )

我的 PointOfInterest 实体:

>     @Entity(tableName = "points_tbl", foreignKeys = [
>          ForeignKey(
>             entity = Route::class,
>             parentColumns = ["id"],
>             childColumns = ["route_id"],
>             onDelete = CASCADE,
>             onUpdate = CASCADE
>         )]) data class PointOfInterest(
>         @PrimaryKey(autoGenerate = false) val id: Int,
>         @ColumnInfo(name = "title") val title: String,
>         @ColumnInfo(name = "description") val description: String,
>         @ColumnInfo(name = "latitude") val latitude: Double,
> 
>  @ColumnInfo(name = "longitude") val longitude: Double,
>     @ColumnInfo(name = "image_url") val imageUrl: String,
>     @ColumnInfo(name = "route_id") val routeId: Int )

关系为 1-N 的实体:

data class RouteWithPointsOfInterest(
    @Embedded val route: Route,
    @Relation(
        parentColumn = "id",
        entityColumn = "route_id"
    ) val pointsOfInterest: List<PointOfInterest>
)

您可以在此处克隆项目

https://github.com/albertbuigues/Touristics

【问题讨论】:

    标签: android kotlin android-room


    【解决方案1】:

    我相信您正在描述如果在构建数组时使用该数组而不是在最终构建数组时使用该数组会发生什么。

    这是在第一次迭代中添加单个 PointOfInterest。但是,在第二次迭代中,数组有 2 个元素(第一个和另一个),当您尝试插入两个 PointsOfInterest 的列表时,第一次插入出现问题,因为尝试插入 duplicate。

    • 您可以通过使用@Insert(onConflict = IGNORE) 来解决此问题,冲突(对现有 id 的尝试)将被忽略。

    但是,您应该等到 ListOfPoints 数组构建完成后再一次性插入。所以:-

    private fun getRoutePoints(routeId: String) {
        val dbReference = FirebaseDatabase.getInstance().getReference("/routes/$routeId")
        val listOfPoints: MutableList<PointOfInterest> = mutableListOf()
        dbReference.child("pointsOfInterest").get().addOnSuccessListener { pointsArray ->
            pointsArray.children.forEach { point ->
                val dataMap = point.value as Map<*, *>
                val routeIdToInsert = routeId.toInt()
                val id = point.key!!.toInt()
                val pointOfInterest = PointOfInterest(
                    id = id,
                    title = dataMap["title"].toString(),
                    description = dataMap["description"].toString(),
                    latitude = dataMap["latitude"].toString().toDouble(),
                    longitude = dataMap["longitude"].toString().toDouble(),
                    imageUrl = dataMap["imageUrl"].toString(),
                    routeId = routeIdToInsert
                )
                listOfPoints.add(id, pointOfInterest)
                /* MOVED
                if (pointsArray.children.count() == listOfPoints.size) {
                    CoroutineScope(Dispatchers.IO).launch {
                        AppDatabase.getInstance(application).routeDao.insertRoutePoints(listOfPoints)
                    }
                }
                 */
            }
            if (listOfPoints.size > 0 ) {
                CoroutineScope(Dispatchers.IO).launch {
                    AppDatabase.getInstance(application).routeDao.insertRoutePoints(listOfPoints)
                }
            }
        }
    }
    

    如果insertRoutePoints Dao 更改为fun insertRoutePoints(points: List&lt;PointOfInterest&gt;): Array&lt;Long&gt;,则返回的数组将具有数组相应元素中相应插入行的 id。如果该值为 -1,而不是正值,则它没有被插入。因此,您可以确定实际插入了多少。

    处理整个数组/列表也意味着所有插入都将在单个事务中完成。而不是许多单独的交易。 @Insert 不需要使用@Transaction,它将是单个事务。

    【讨论】:

    • 不行,只写route_id (foreign_key) = 0的,不写route_id = 1的,我会继续尝试
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-21
    相关资源
    最近更新 更多