Как выполнить множественную вставку данных в 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, и уверен, что найдутся люди с опытом которые смогут объяснить недостатки этого кода, и предложить более "качественный" и шустрый вариант.