无论情况如何,内容提供商列 ID 都始终是唯一的吗?

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

例如

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 数据库中删除的数据?

android-room android-contentprovider android-contentresolver
1个回答
0
投票

仅将列命名为 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 也必须是唯一的,两者的冲突都会导致插入被忽略。

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