You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Room删除操作失效:Dao测试中删除后数据未减少求助

基于Room的Android项目删除数据测试失败问题排查

在基于Room的Android项目中,测试Dao对象时,插入和查询数据的测试均正常,但删除数据的测试始终失效。调用delete和deleteById方法后,通过getAll查询到的数据数量与删除前一致。

实体类代码

@TypeConverters(TagConverters::class)
@Entity(
    tableName = "tag",
    indices = [ // Enforce tag_name to be unique
        Index(value = ["tag_name"], unique = true)
    ]
)
data class TagEntity(
    @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "tag_id") val id: Long = 0,
    @ColumnInfo(name = "tag_name") val name: TagName,
    val icon: String? = null,
    val color: String? = null
)

Dao代码

@Dao
interface TagDao : BaseDao<TagEntity> {
    @Query("SELECT * FROM tag WHERE tag_id = :id")
    suspend fun getById(id: Long): TagEntity

    @Query("SELECT * FROM tag WHERE tag_name = :name")
    suspend fun getByName(name: String): TagEntity

    @Query("SELECT * FROM tag")
    suspend fun getAll(): List<TagEntity>

    /**
    Some stuff that I have tested
    @Delete
    override suspend fun delete(vararg theme: ThemeEntity)
    @Query("DELETE FROM theme WHERE theme_id  LIKE :id")
    */

    @Query("DELETE FROM tag WHERE tag_name = :id")
    suspend fun deleteById(id: Long)
}

BaseDao代码

@Dao
interface BaseDao<T> {
    @Insert
    suspend fun insert(obj: T): Long

    @Insert
    suspend fun insert(vararg obj: T)

    @Upsert
    suspend fun upsert(vararg obj: T)

    @Delete
    suspend fun delete(obj: T)
}

测试代码

class TagDaoTest {
    private lateinit var database: AppDatabase
    private lateinit var tagDao: TagDao

    @Before
    fun createDb() {
        val context = ApplicationProvider.getApplicationContext<Context>()
        database = Room.inMemoryDatabaseBuilder(
            context, AppDatabase::class.java
        ).build()

        tagDao = database.tagDao()
    }

    @Test
    fun tagDao_delete_a_tag() = runTest {
        val tag0 = newTag(name = TagName("HISTORY"))
        val tag1 = newTag(name = TagName("Science"))
        val tag2 = newTag(name = TagName("Nature"))
        val tag3 = newTag(name = TagName("Sport"))
        val tag4 = newTag(name = TagName("culture"))

        tagDao.insert(tag0)
        tagDao.insert(tag1)
        tagDao.insert(tag2)
        tagDao.insert(tag3)
        tagDao.insert(tag4)

        val retrievedTags = tagDao.getAll()
        Assert.assertEquals(5, retrievedTags.size)

        tagDao.delete(tag1)
        tagDao.deleteById(tag2.id)

        val retrievedTags2 = tagDao.getAll()
        Assert.assertEquals(3, retrievedTags2.size)
    }
}

private fun newTag(
    name: TagName,
    date: LocalDate = LocalDate(year= 1979, monthNumber= 11, dayOfMonth = 25)
) = TagEntity(
    name = name,
    icon = null,
    color = null)

报错信息

java.lang.AssertionError: expected:<3> but was:<5>
at org.junit.Assert.failNotEquals(Assert.java:835)
at eu.aklal.app.core.database.TagDaoTest$tagDao_delete_a_tag$1.invokeSuspend(TagDaoTest.kt:93)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at eu.aklal.app.core.database.TagDaoTest.tagDao_delete_a_tag(TagDaoTest.kt:73)

问题原因及解决方案

1. deleteById方法SQL语句错误

当前deleteById的SQL是DELETE FROM tag WHERE tag_name = :id,但参数id是Long类型的主键值,而tag_name对应数据库中是TagName转换后的字符串,两者完全不匹配,导致这条删除语句找不到任何数据。

修正方法:
把SQL语句改为根据主键tag_id匹配:

@Query("DELETE FROM tag WHERE tag_id = :id")
suspend fun deleteById(id: Long)

2. 调用@Delete方法时实体主键不匹配

你调用tagDao.delete(tag1)时,传入的tag1是插入前创建的对象,它的id还是初始值0。但插入Room后,数据库会自动生成自增的主键id,这个值不会自动同步回原对象。Room的@Delete注解是根据实体的主键值来匹配数据库中的数据的,所以用id为0的对象去删除,根本找不到对应的数据。

修正方法(二选一):

  • 方式一:插入后获取主键并更新实体
    利用insert方法返回的主键值,更新原对象的id,或者直接查询数据库中的实体再删除:

    // 插入时获取返回的主键id
    val tag1Id = tagDao.insert(tag1)
    // 查询数据库中的真实实体
    val tag1FromDb = tagDao.getById(tag1Id)
    // 用真实实体执行删除
    tagDao.delete(tag1FromDb)
    
  • 方式二:统一用deleteById方法删除
    既然已经有了deleteById方法,插入后直接用返回的id调用该方法即可:

    val tag1Id = tagDao.insert(tag1)
    tagDao.deleteById(tag1Id)
    

内容的提问来源于stack exchange,提问作者eqtèöck

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 02:36:02