房间持久化库。删除全部。

274

如何使用Room Persistence Library删除特定表上的所有条目? 我需要删除表,但是我找不到任何关于如何做到这一点的信息。

只有在数据库迁移或加载所有条目并删除它们时才能实现 :)


21
从 Room 1.1.0 开始,您可以使用 clearAllTables() 方法,它会“删除所有被注册为实体的表中的所有行”。我已经在下面的答案中包含了这个信息,但为了更加明确,我在此重复一遍。 - Dick Lucas
3
因为有多个人建议使用 clearAllTables(),我忍不住要指出OP非常清楚地说:“如何删除特定表格中的所有条目”。 - Chucky
9个回答

621

你可以创建一个DAO方法来实现这个功能。

@Dao 
interface MyDao {
    @Query("DELETE FROM myTableName")
    public void nukeTable();
}

4
啊,我没有想到那一点。我认为@Query只适用于返回结果集的事物(类似于rawQuery())。非常棒! - CommonsWare
1
@yigit,我可以请求@Delete不带参数并从表中删除所有内容吗?我正在尝试查找Room的跟踪器以进行存档... - Felipe Duarte
4
注意!对于房间alpha4版本而言,这种技术会导致Gradle构建失败:https://issuetracker.google.com/issues/63608092 - yshahak
2
Ids 怎么样?我这样做了,但是表 Ids 继续递增。在真实的表中,Ids 也会被删除以重新从 0 开始。 - Ioane Sharvadze
8
有没有一种方法可以确定查询是否成功运行或是否出现错误? - Aditya Ladwa
显示剩余5条评论

145

从版本1.1.0开始,你可以使用clearAllTables()方法来做到以下操作:

删除所有在此数据库中作为entities()注册的表中的所有行。


67
注意:clearAllTables() 是异步的,没有办法知道它何时完成。 - Alexey
2
@Alexey,在执行clearAllTables之后尝试保存数据会有任何问题吗?也就是说,在清空之后它只会尝试插入新数据?如果是这样的话,我可以接受。 - FirstOne
3
@FirstOne clearAllTables 基本上只是在新的后台线程上启动一个事务。它会删除所有表中的数据,然后提交该事务。如果您稍后启动事务,则不会有问题。话虽如此,如果您在调用 clearAllTable 后立即尝试插入一些数据,则可能会在 clearAllTable 开始事务之前启动插入操作,并且您将失去所有数据。如果您需要在调用 clearAllTable 后立即插入新数据,则至少要添加一些延迟时间。 - Alexey
2
@Alexey 有没有办法使用回调方法或类似的方式来确定删除事务的状态?换句话说,如果删除事务完成了,则继续执行插入数据方法。 - AJW
2
clearAllTables() 不是异步操作,但它强制你不要从主线程调用它。 - Demigod
显示剩余6条评论

43

如果想要从Room中的表中删除一个条目,只需调用此函数:

@Dao
public interface myDao{
    @Delete
    void delete(MyModel model);
}

更新:如果您想删除整个表,请调用以下函数:

  @Query("DELETE FROM MyModel")
  void delete();

注意:这里的MyModel是一个表名。


在使用您的更新代码后,我遇到了以下错误:抽象DAO方法必须用以下注释之一进行注释:Insert、Delete、Query、Update、RawQuery中的一个且仅一个。 void delete(); - bramastaVic

15

使用下面类似的RXJava代码和clearAllTables()来避免java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.

Completable.fromAction(new Action() {
        @Override
        public void run() throws Exception {
            getRoomDatabase().clearAllTables();
        }
    }).subscribeOn(getSchedulerProvider().io())
            .observeOn(getSchedulerProvider().ui())
            .subscribe(new Action() {
                @Override
                public void run() throws Exception {
                    Log.d(TAG, "--- clearAllTables(): run() ---");
                    getInteractor().setUserAsLoggedOut();
                    getMvpView().openLoginActivity();
                }
            }, new Consumer<Throwable>() {
                @Override
                public void accept(Throwable throwable) throws Exception {
                    Log.d(TAG, "--- clearAllTables(): accept(Throwable throwable) ----");
                    Log.d(TAG, "throwable.getMessage(): "+throwable.getMessage());


                }
            });

9

当我使用RxJava在后台执行删除任务时,我遇到了问题。这是我最终解决它的方法:

@Dao
interface UserDao {
    @Query("DELETE FROM User")
    fun deleteAll()
}

并且

fun deleteAllUsers() {
    return Maybe.fromAction(userDao::deleteAll)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe ({
            d("database rows cleared: $it")
        }, {
            e(it)
        }).addTo(compositeDisposable)
}

6
在使用 Kotlin 时,您可以只需将其包装在 thread {} 中,而无需费时地处理 RxJava。 - Erik

8

以下是从碎片(Fragment)中执行的方法。

fun Fragment.emptyDatabase() {
    viewLifecycleOwner.lifecycleScope.launchWhenCreated {
        withContext(Dispatchers.IO) {
            Database.getInstance(requireActivity()).clearAllTables()
        }
    }
}


如果您从活动中清空数据库,请使用以下方法:
fun Activity.emptyDatabase() {
    // create a scope to access the database from a thread other than the main thread
    val scope = CoroutineScope(Dispatchers.Default)
    scope.launch {
        SitukaDatabase.getInstance(this@emptyDatabase).clearAllTables()
    }
}

也可以从主线程调用clearAllTables方法。我没有尝试过,但我注意到Android Studio不会将此调用识别为暂停函数。


3

结合Dick Lucas的说法和其他StackOverFlow帖子中的重置自增量,我认为以下方法可以解决问题:

fun clearAndResetAllTables(): Boolean {
    val db = db ?: return false

    // reset all auto-incrementalValues
    val query = SimpleSQLiteQuery("DELETE FROM sqlite_sequence")

    db.beginTransaction()
    return try {
        db.clearAllTables()
        db.query(query)
        db.setTransactionSuccessful()
        true
    } catch (e: Exception){
        false
    } finally {
        db.endTransaction()
    }
}

说实话,我发现最简单的方法是通过context.deleteDatabase(“name”)来完成,然后在第一次访问时通过Room.databaseBuilder()。addCallback重新实例化和填充数据库。 - Bink
sqlite_sequence是什么? - RoyalGriffin

2
为了在不滥用@Query注释的情况下使用 Room,首先使用@Query选择所有行并将它们放入列表中,例如: @Query("SELECT * FROM your_class_table")
List`<`your_class`>` load_all_your_class();

将他的列表放入删除注释中,例如:

@Delete

void deleteAllOfYourTable(List`<`your_class`>` your_class_list);

2
这是我在Kotlin中完成它的方式。
  1. Inject room db in the activity using DI (Koin).

     private val appDB: AppDB by inject()
    
  2. Then you can simply call clearAllTables()

private fun clearRoomDB() {
    GlobalScope.launch {
        appDB.clearAllTables()
        preferences.put(PreferenceConstants.IS_UPLOADCATEGORIES_SAVED_TO_DB, false)
        preferences.put(PreferenceConstants.IS_MEMBERHANDBOOK_SAVED_TO_DB, false)
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接