例如
MediaStore.Audio.Media._ID.
我问的原因是因为我正在读取音乐数据并将它们写入 Room 数据库。我不希望出现无法添加歌曲的情况,因为它使用的是我的 Room 数据库中存储的 ID。
这就是我将数据写入 Room 的方式。我必须使用这种冲突策略,否则它会不断添加已删除的歌曲。
@Transaction
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun addSongs(song: SongTrack)
我有一个查询,它删除了
SongTrack
实体中除 ID/DbId 之外的所有内容(ID/DbId 只是为了记录已删除的歌曲)。
@Query("UPDATE songtrack SET albumUri = null,
songTitle = '', albumTitle= '' " + ", genre = '', image = '' WHERE id =
:songId" )
fun removeBySongId(songId: Int)
实体如下:
@Entity
data class SongTrack(
@PrimaryKey(autoGenerate = false)
var dbId: Int,
val id: Int,
val songTitle: String,
val artistName: String,
val albumUri: String?,
val image: String?,
val duration: Long,
val albumTitle: String,
val genre: String)
希望这一切都有道理。如果列 ID 永远是唯一的,即使有人删除了手机上的数据,我的方法也是安全的。
否则,如何防止 Room 添加回我从 Room 数据库中删除的数据?
仅将列命名为 id 并不能使其成为唯一列。使列唯一的原因是该列上有唯一索引。
在您的情况下,dbId列/字段具有隐式
UNQIUE index
,因为它被定义为PrimaryKey
。因此 dbId 列必须是 UNIQUE value
。
如果尝试添加一行,其中 dbId 的值已存在于另一行中,则会出现
UNIQUE conflict
,正如您所发现的,您可以使用 INSERT OR IGNORE
(即 onConflictStrategy
)来消除失败IGNORE
。
因此,如果表中已存在 dbId 值,您的代码将阻止添加另一行。
问题说:-
我有一个查询,它从 SongTrack 实体中删除除 ID/DbId 之外的所有内容(ID/DbId 只是记录已删除的歌曲)。
但是,id列/字段没有唯一索引,因此任何行都可以具有任何值。
如果您希望该值也是唯一的,那么您不能有多个主键(尽管您可以有一个由多个列组成的主键(复合主键),但它是唯一的列的组合,而不是一个单独的专栏)。
Room 不通过列/字段注释来满足复合主键或
UNIQUE
索引的需求。您必须使用 primaryKeys
注释的 indices
和/或 @Entity
参数来定义这些。
如果您希望 id 列也是唯一的(即 dbId 列),那么您必须使用
indices
参数,例如
@Entity(indices = [Index("id", unique = true)])
添加上述内容后,dbId 必须是唯一的,id 也必须是唯一的,两者的冲突都会导致插入被忽略。