Sergi Mascaró
08/05/2025, 3:25 PM@Transaction
in the right order to satisfy the FKs. That is:
1. insertA()
2. allB.foreach { insertB() }
3. allC.foreach { insertC() }
Now, after months of debugging what is going on, I noticed when adding query logging that sometimes a C will be inserted before all Bs have been inserted and cause a foreign key violation. I found out about deffered foreign keys and I was extremely happy, until I realized that it's broken and Google is not fixing it.
Any ideas or experiences? I'm quite lost, it shouldn't be a rare scenario...Hristijan
08/05/2025, 5:14 PMSergi Mascaró
08/06/2025, 9:01 AMHristijan
08/06/2025, 9:02 AMSergi Mascaró
08/06/2025, 9:05 AM@Insert
queries or insert `@Query("INSERT...")`s? I'm really trying to avoid the last one as it will be a hell to maintain. But in general, if you didn't use transactions at all, how did you handle rollbacks in case there were any issue? That's my other concern 😬Hristijan
08/06/2025, 9:07 AMHristijan
08/06/2025, 9:09 AMHristijan
08/06/2025, 9:11 AMSergi Mascaró
08/06/2025, 9:21 AM@Insert
, then it is no longer atomic and there's no promise it will wait for the row to be inserted before continuing with the next one. Now I'm playing around with making each insert return the row id. It wouldn't make sense that the execution should be able to continue if you need the inserted row id. Hopefully this enforces some more sequentialitySergi Mascaró
08/06/2025, 10:29 AMSergi Mascaró
08/06/2025, 10:29 AMAhmed
09/06/2025, 6:10 PM@Insert
fun insertBs(b: List<B>)
@Insert
fun insertCs(c: List<C>)
And if the list is very large, you can maybe use windowed
or chunked
Sergi Mascaró
09/19/2025, 10:19 AMAhmed
09/19/2025, 11:14 AM@Transaction
fun insertAll(
a: List<A>,
b: List<B>,
c: List<C>,
) {
a.chunked(100).forEach{ insertA(it) }
b.chunked(100).forEach{ insertB(it) }
c.chunked(100).forEach{ insertC(it) }
}
This ensures the order and wraps all of the logic in a transaction.Sergi Mascaró
09/22/2025, 3:37 PMx.forEach{ insertX(it) }
, since splitting a list in chunks doesn't make it happen in different transactions. I think the main reason why the other solution works is because then we leave it to room to execute the transaction of inserting all the entities of one type, instead of iterating ourselves.