Room Persistence Library
Database Management
Android Development
Data Persistence
SQLite

Room persistance library. Delete all

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Deleting all records with Room is simple at SQL level, but production-safe implementation needs more than one DELETE query. You need correct threading, transaction boundaries, and UI state coordination so users do not see stale data or accidental data loss. A clean architecture puts delete-all logic in DAO and repository layers, then triggers it from ViewModel with explicit confirmation.

Core Sections

Define explicit DAO operation for destructive delete

Room works best when destructive actions are named clearly and return useful signals such as affected row count.

kotlin
1import androidx.room.Dao
2import androidx.room.Query
3
4@Dao
5interface NoteDao {
6    @Query("DELETE FROM notes")
7    suspend fun deleteAll(): Int
8}

Returning affected rows helps analytics and debugging. If your use case does not need count, Unit is also fine, but explicit count is often useful.

Keep delete-all outside UI layer

Do not call DAO directly from activities or fragments. Use repository so side effects and logging are centralized.

kotlin
1class NoteRepository(
2    private val noteDao: NoteDao
3) {
4    suspend fun clearAllNotes(): Int {
5        return noteDao.deleteAll()
6    }
7}

This makes testing easier and keeps UI code focused on state presentation.

Trigger from ViewModel with coroutine scope

Delete-all should run on background dispatcher through suspend functions and viewModelScope.

kotlin
1import androidx.lifecycle.ViewModel
2import androidx.lifecycle.viewModelScope
3import kotlinx.coroutines.flow.MutableStateFlow
4import kotlinx.coroutines.flow.StateFlow
5import kotlinx.coroutines.launch
6
7class NoteViewModel(
8    private val repo: NoteRepository
9) : ViewModel() {
10
11    private val _status = MutableStateFlow("idle")
12    val status: StateFlow<String> = _status
13
14    fun deleteEverything() {
15        viewModelScope.launch {
16            _status.value = "deleting"
17            val removed = repo.clearAllNotes()
18            _status.value = "deleted:$removed"
19        }
20    }
21}

State transitions should be explicit so UI can disable buttons while operation runs.

Use transactions for multi-table cleanup

If your reset operation spans several tables, wrap all delete queries in one transaction.

kotlin
1import androidx.room.Database
2import androidx.room.RoomDatabase
3import androidx.room.withTransaction
4
5@Database(entities = [/* entities */], version = 1)
6abstract class AppDb : RoomDatabase() {
7    abstract fun noteDao(): NoteDao
8    abstract fun tagDao(): TagDao
9}
10
11class MaintenanceRepository(private val db: AppDb) {
12    suspend fun clearAllData() {
13        db.withTransaction {
14            db.tagDao().deleteAll()
15            db.noteDao().deleteAll()
16        }
17    }
18}

This prevents partial cleanup if one query fails mid-operation.

Coordinate with foreign keys and cascades

If tables are related, decide whether manual delete order or cascade rules should handle dependencies. If cascade is enabled, deleting parent rows may remove children automatically. Validate this behavior with tests instead of assumptions.

Schema migrations can change foreign-key behavior. Keep cascade expectations documented near DAO methods.

Handle user confirmation and undo strategy

Delete-all is destructive. Add confirmation dialog and clear messaging. For critical data, consider soft-delete or backup export before wipe.

Typical UX flow:

  • user taps clear,
  • confirm dialog appears,
  • operation runs with loading state,
  • success or failure feedback shown.

Without confirmation, accidental tap can permanently remove data.

Refresh observers and cached UI correctly

After deletion, list screens should update immediately. If UI still shows old data, verify Flow or LiveData subscriptions and caching layers.

Room invalidation usually refreshes observed queries, but custom caches in repository or adapter layers may need manual reset.

Performance considerations for large tables

Mass delete on huge tables may take noticeable time. For very large datasets, evaluate whether dropping and recreating database is faster for full reset scenarios. If using delete-all frequently, monitor operation duration on lower-end devices.

Avoid running many separate delete calls without transaction; this increases overhead and risk.

Testing strategy

Add tests for:

  • delete-all row count,
  • multi-table transaction rollback,
  • UI state transitions around deletion,
  • foreign-key cascade behavior.

Instrumentation tests are useful for verifying real Room behavior on device or emulator.

Common Pitfalls

  • Executing delete-all from main thread and freezing UI.
  • Calling DAO directly from UI components without repository boundary.
  • Clearing multiple tables without transaction guarantees.
  • Assuming cascade deletes work without schema-level verification.
  • Triggering destructive operation without explicit user confirmation.

Summary

  • Implement clear delete-all DAO methods with explicit intent.
  • Execute destructive operations through repository and ViewModel layers.
  • Use transactions for multi-table cleanup consistency.
  • Coordinate Room updates with UI state and observer refresh.
  • Add confirmation, tests, and performance monitoring for safe production behavior.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.