Как выполнить множественную вставку данных в ROOM (DAO, Kotlin, Android)

Совсем недавно начал увлекаться программированием на Kotlin, делаю проект на Android 4.3 (оу, да) и изначально написал вставку в БД на SQLiteOpenHelper. Вставка 7000 строк заняла около 5 секунд. Сейчас хочется идти в ногу со временем и есть желание переписать код на Room (DAO). Но текущий написанный мной код вставки в БД занимает около 24 секунд, что прилично больше. Поэтому суть вопроса: Как я бы мог улучшить код вставки в БД, зная: есть API endpoint, обращаясь к которому получаю список данных в виде json:

    {
    "status": "success",
    "count": 2,
    "drop": 0,
    "version": "1",
    "info": [
        {
            "id": "0493c697-b098-11ef-ad67-080027b70a93",
            "idS": "a64d796f-10fb-11ea-baa0-ac1f6bb3e8a9",
            "date": "2024-12-03 09:00:00",
            "dateR": null,
            "type": "type1",
            "status": "10",
            "dateCreate": "2024-12-15 14:31:19",
            "dateUpdate": null,
            "version1c": "AAAAAAwI40k=",
            "number1c": "00-00000973",
            "version": null,
            "thisDelete": "0",
            "idDT": null,
            "positions": [
                {
                    "id": "0493c697-b098-11ef-ad67-080027b70a93",
                    "index": "1",
                    "idN": "dad7e625-c34e-11e6-80d7-c860006aa174",
                    "idK": null,
                    "count": "-3.0000"
                },
                {
                    "id": "0493c697-b098-11ef-ad67-080027b70a93",
                    "index": "2",
                    "idN": "5b6eba01-7a19-11ee-ad5c-080027b70a93",
                    "idK": null,
                    "count": "7.0000"
                },
                {
                    "id": "0493c697-b098-11ef-ad67-080027b70a93",
                    "index": "3",
                    "idN": "19536f39-60b2-11df-88aa-005056c00008",
                    "idK": null,
                    "count": "1.0000"
                },
                {
                    "id": "0493c697-b098-11ef-ad67-080027b70a93",
                    "index": "4",
                    "idN": "19536f3a-60b2-11df-88aa-005056c00008",
                    "idK": null,
                    "count": "7.0000"
                }
            ]
        },
        {
            "id": "09d0d740-ae3b-11ef-ad67-080027b70a93",
            "idS": "52b6abb5-e169-11e3-9413-c860006aa174",
            "date": "2024-12-02 09:00:00",
            "dateR": null,
            "type": "tovar",
            "status": "10",
            "dateCreate": "2024-12-15 14:31:19",
            "dateUpdate": null,
            "version1c": "AAAAAAwCzeY=",
            "number1c": "00-00000972",
            "version": null,
            "thisDelete": "0",
            "idDT": null,
            "positions": [
                {
                    "id": "09d0d740-ae3b-11ef-ad67-080027b70a93",
                    "index": "1",
                    "idN": "dad7e625-c34e-11e6-80d7-c860006aa174",
                    "idK": null,
                    "count": "-3.0000"
                },
                {
                    "id": "09d0d740-ae3b-11ef-ad67-080027b70a93",
                    "index": "2",
                    "idN": "5b6eba01-7a19-11ee-ad5c-080027b70a93",
                    "idK": null,
                    "count": "8.0000"
                }
            ]
        }
    ]
}

И так далее 7000 строк. На данный момент мой кривой код вставки выглядит так: (ViewModel)

fun processResponseDataDocs(docs: String, idDevice: String): Boolean {
    var success = false
    try {
        val type = object : TypeToken<ResponseData<Docs>>() {}.type
        val response: ResponseData<Docs> = Gson().fromJson(docs, type)

        if (response.status != "success") return false

        val existingDocs = dao.getDocsWithStatus().associateBy { it.id }

        val (docsToInsert, positionsToInsert) = response.info
            .filter { doc ->
                val existingDoc = existingDocs[doc.id]
                existingDoc == null ||
                        (idDevice != existingDoc.idDevice &&
                                (existingDoc.status == "0" || existingDoc.status == "10"))
            }
            .let { filteredDocs ->
                val docs = filteredDocs.map { doc ->
                    DocsInfo(
                        id = doc.id,
                        idS = doc.idS,
                        date = doc.date,
                        dateR = doc.dateR,
                        type = doc.type,
                        status = doc.status,
                        dateCreate = doc.dateCreate,
                        dateUpdate = doc.dateUpdate,
                        version = doc.version,
                        version1c = doc.version1c,
                        number1c = doc.number1c,
                        thisDelete = doc.thisDelete,
                        idDT = doc.idDocTara,
                        idDevice = doc.idDevice
                    )
                }

                val positions = filteredDocs.flatMap { doc ->
                    doc.positions.map { pos ->
                        PositionsInfo(
                            id = pos.id,
                            index = pos.index,
                            idN = pos.idN,
                            count = pos.count,
                            idK = pos.idK
                        )
                    }
                }

                Pair(docs, positions)
            }

        database.runInTransaction {
            dao.insertOrUpdateDocs(docsToInsert)
            positionDao.insertOrUpdatePositions(positionsToInsert)
        }

        success = true
    } catch (e: Exception) {
        success = false
    }
    return success
}

(dao interface)

@Transaction
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertOrUpdateDocs(docs: List<DocsInfo>)

и почти тоже самое для dao positions.

Entity выглядит так:

@Entity(tableName = "docs")
data class DocsInfo(
    @PrimaryKey @ColumnInfo(name = "id")
    val id: String,
    @ColumnInfo(name = "idS")
    val idS: String,
    @ColumnInfo(name = "date")
    val date: String,
    @ColumnInfo(name = "dateR")
    val dateR: String?,
    @ColumnInfo(name = "type")
    val type: String,
    @ColumnInfo(name = "status")
    val status: String,
    @ColumnInfo(name = "dateCreate")
    val dateCreate: String,
    @ColumnInfo(name = "dateUpdate")
    val dateUpdate: String?,
    @ColumnInfo(name = "version1c")
    val version1c: String,
    @ColumnInfo(name = "number1c")
    val number1c: String,
    @ColumnInfo(name = "version")
    val version: String?,
    @ColumnInfo(name = "thisDelete")
    val thisDelete: String,
    @ColumnInfo(name = "idDT")
    val idDT: String?,
    @ColumnInfo(name = "idDevice")
    val idDevice: String?
)
@Entity(
    tableName = "positions",
    foreignKeys = [ForeignKey(
        entity = DocsInfo::class,
        parentColumns = ["id"],
        childColumns = ["id"],
        onDelete = ForeignKey.CASCADE
    )],
    indices = [Index(value = ["id"])]
)
data class PositionsInfo(
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "id")
    val id: Int = 0,
    @ColumnInfo(name = "id")
    val id: String,
    @ColumnInfo(name = "index")
    val index: Int,
    @ColumnInfo(name = "idN")
    val idN: String?,
    @ColumnInfo(name = "idK")
    val idK: String?,
    @ColumnInfo(name = "count")
    val count: Double
)

Я верю в stackoverflow, и уверен, что найдутся люди с опытом которые смогут объяснить недостатки этого кода, и предложить более "качественный" и шустрый вариант.


Ответы (0 шт):