如何限制 Android Room Dao 内部方法的使用

问题描述 投票:0回答:2

我在 Room 中有一个 Transaction,就像文档中给出的那样。

@Dao
abstract class SongDao {
    @Insert
    abstract fun insert(song: Song)
    @Delete
    abstract fun delete(song: Song)
    @Transaction
    fun insertAndDeleteInTransaction(newSong: Song, oldSong: Song) {
        // Anything inside this method runs in a single transaction.
        insert(newSong)
        delete(oldSong)
    }
}

我的用例是我不想在 Dao 中公开

delete()
以便从 Dao 外部调用。
可能吗?如果是的话,怎么办?

创建方法

private
不是一个选项,因为 Kotlin 的接口中不允许使用
private
方法。

android kotlin interface android-room
2个回答
0
投票

您可以从构建的数据库实例中通过 openHelper 函数获取 SupportSQLiteDatabase 并使用删除、execSQL 或查询函数。

例如沿着以下路线:-

    db = TheDatabase.getInstance(this)
    db.openHelper.writableDatabase.delete("the_table","the_column=?", arrayOf("the_value"))
    db.openHelper.writableDatabase.execSQL("DELETE FROM the_table WHERE the_column =?", arrayOf("the_value"))
    db.openHelper.writableDatabase.query("DELETE FROM the_table, WHERE the_column =?", arrayOf("the_value"))
  • 显然你只会使用以上之一,
  • 以上也只是一个例子,
  • 请注意,由于这些超出了 Room 编译时检查 SQL 有效性的范围,因此如果 SQL 不正确,您可能会遇到运行时错误,例如不正确的表名。

基于您的代码和嵌入的歌曲数据类的示例使用:-

class MainActivity : AppCompatActivity() {
    lateinit var db: TheDatabase
    lateinit var dao: AllDao
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        db = TheDatabase.getInstance(this)
        dao = db.getAllDao()

        insertAndDeleteInTransaction(Song(songName = "The Song"),Song(100,"whatever"))
    }

    private fun insertAndDeleteInTransaction(newSong: Song, oldSong: Song ) {
        val helper=db.openHelper.writableDatabase
        helper.beginTransaction()
        val newSongRowid = dao.insert(newSong)
        val numberOfSongsDeleted = helper.delete("song","songId=?", arrayOf(oldSong.songid))
        helper.setTransactionSuccessful() /* IF not set then changes would be rolled back */
        helper.endTransaction()
    }

    @Entity
    data class Song(
        @PrimaryKey
        var songid: Long?=null,
        var songName: String
    )
} 
  • 显然 Song 类不会在 Activity 中定义,这里包含它只是为了示例
  • oldSong 有一个名为whatever 的歌曲名称,这表明歌曲名称是什么并不重要。 PrimaryKey 用于确定要删除哪一行。
    • 在这个例子中,你可以看到songId是主键,并且假设songId为100的歌曲存在(如果不存在,则numberOfSongsDelete将为0,即如果没有任何可删除的内容,DELETE不会失败)
  • 插入使用@Dao注解的接口/抽象类中的insert函数。
  • 请注意,newSongRowid 将是插入行的 rowid,如果由于某种原因无法插入该行并且不是失败,则为 -1。

rowid

所有表(除了一些罕见的例外)都有一个名为 rowid 的列。在 Song 表作为主键的情况下,songId 是整数类型(Long、Int、Byte ....),那么它是 rowid 的别名。

因此上面的 newSong 插入,没有指定 SongId 的值,将会生成该值(不需要

autoGenerate = true
)。

  • 例如如果最后插入的歌曲是id为100的歌曲,那么newSong的songId可能是101。

您可能希望参考 https://www.sqlite.org/rowidtable.html 以及 https://sqlite.org/autoinc.html (如果您使用 autoGenerate=true,则应用自动增量)


0
投票

我认为你应该能够将删除功能设为内部功能。我在 Room 文档中没有看到 DAO 中有任何可见性要求。如果您将 DAO 分离到单独的模块中,则删除功能的可见性将仅限于该模块内。

© www.soinside.com 2019 - 2024. All rights reserved.