房间数据库重复相同的主键项

Roomdatabase Duplicates Same Primarykey Item

我正在从通知中获取消息并将其保存到 Roomdatabase。问题是我使用用户名作为主键,但是当数据到来时具有相同的主键,roomdatabase 将其保存为一个新对象。我用了 OnConflictStrategy.REPLACE 但它不起作用。这是我的 类。注意:我通过使用单独的实体对象来保存用户和消息。

@Entity
data class UserEntity(
   @PrimaryKey(autoGenerate = false) val user: String,
   val lastMessage: String,
   val lastTime: String
)

DAO

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUser(entity: UserEntity)

传入数据

    val from = bundle.getString(NotificationCompat.EXTRA_TITLE)
    val message = bundle.getString(NotificationCompat.EXTRA_TEXT)

    val filteredFrom = from?.replace(
       "\(.*\)".toRegex(),
       ""
    )?.filter {!it.isWhitespace()}

保存方法

repository.addUserToRoomDatabase(
                        UserEntity(
                        user = filteredFrom,
                        lastMessage = message,
                        lastTime = time
                    )
                )

我相信您的问题不是由于 Room 的明显处理不当造成的,而是问题出在其他地方,如果您使用 App Inspection 检查实际数据库,那么您会发现确实如此。

演示

使用你的 UserEntity class 和你的 insertUser 函数(虽然没有暂停)和一个额外的 DAO 来提取数据(所以 @Dao 注释 class AllDAO)是:-

@Dao
interface AllDAO {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertUser(entity: UserEntity)

    @Query("SELECT * FROM userentity")
    fun getAllUsers(): List<UserEntity>
    
}

连同下面的演示(以及一个合适的@Database注解class):-

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()
        dao.insertUser(UserEntity("Fred","1st Fred","0000"))
        dao.insertUser(UserEntity("Mary","1st Mary","1111"))
        dao.insertUser(UserEntity("Jane","1st Jane","2222"))
        logAllUsers("_RUN1")
        dao.insertUser(UserEntity("Fred","2nd Fred","4444"))
        dao.insertUser(UserEntity("Mary","2nd Mary","5555"))
        dao.insertUser(UserEntity("Jane","2nd Jane","6666"))
        logAllUsers("_RUN2")


    }
        fun logAllUsers(prefix: String) {
            for (u in dao.getAllUsers()) {
                Log.d("USERINFO${prefix}","User is ${u.user} Last Message is ${u.lastMessage} LastTime is ${u.lastTime}")
            }
        }
}

结果日志中包含:-

2022-04-28 05:50:34.735 D/USERINFO_RUN1: User is Fred Last Message is 1st Fred LastTime is 0000
2022-04-28 05:50:34.735 D/USERINFO_RUN1: User is Mary Last Message is 1st Mary LastTime is 1111
2022-04-28 05:50:34.735 D/USERINFO_RUN1: User is Jane Last Message is 1st Jane LastTime is 2222


2022-04-28 05:50:34.741 D/USERINFO_RUN2: User is Fred Last Message is 2nd Fred LastTime is 4444
2022-04-28 05:50:34.742 D/USERINFO_RUN2: User is Mary Last Message is 2nd Mary LastTime is 5555
2022-04-28 05:50:34.742 D/USERINFO_RUN2: User is Jane Last Message is 2nd Jane LastTime is 6666

也就是说,从输出来看,行被替换而不是重复。

使用 App Inspection,这证实了这种情况,因为它只显示了最后 3 个被替换的行:-

如果using/running以下查询使用应用程序检查SELECT rowid,* FROM userentity则显示:-

这进一步证实了 Room 的行为符合预期。

也就是说,当第一个 运行 时,前 3 个插入将创建具有 rowids 1,2 和 3 的行。

插入第二组时,删除 rowid 1(用户 Fred)的行并插入新行,rowid 将是下一个,即 4,依此类推 (2 --> 5, 3 --> 6)。

如果您确实看到看似重复的行,则很可能用户实际上并不相同。您也许可以通过 App Inspection 使用查询 SELECT rowid,length(user),* FROM userentity

此处再次使用 App Inspection 中的查询使用 INSERT INTO userentity VALUES ('Fred ','ooops','9999') 插入明显错误的行(注意 Fred 之后的 space)

Fred 似乎为 Fred 复制了一行,但 space 有所不同。使用第二个查询可以看出,是的,有 2 行 Fred,但第二个查询有 5 作为 Fred 的长度。

由于您正在“过滤”,那么也许这就是您的问题所在。