, даже когда я ЗНАЮ, что я не пытался вставить другой объект с тем же системным ID
Из вашего описания ошибки и того, что использование REPLACE устраняет проблему, возникает строка в базе данных с тем же system_id, который вы пытаетесь вставить.
Обратите внимание, что приведенное описание немного отличается от вашего. SQLite, для которого Room является в основном оболочкой, не имеет понятия хранения объектов, а хранения данных в строках, каждая строка содержит одинаковое количество элементов (хотя некоторые могут быть нулевыми).
Разница между объектами в приложении и даже если вы приравниваете строку в базе данных к объекту (который он может представлять и будет представлять в комнате), заключается в том, что в базе данных данные сохраняются и остаются в базы данных при перезапуске приложения. Возможно, именно эта настойчивость сбивает вас с толку.
Если вы изменяете / используете
@Query("SELECT * FROM authentication WHERE system_id = :system_id")
suspend fun getAuth(system_id: String): Authentication?
- , имеющий
@Query("SELECT * FROM authentication WHERE system_id = 1")
suspend fun getAuth(): Authentication?
довольно бесполезен, так как позволяет извлечь только 1 Аутентификацию из база данных, которая, вероятно, не существует.
И используйте это перед вставкой, используя system_id, который вы вставляете, это, скорее всего, подтвердит случай. То есть он найдет данные и вернет действительный (ненулевой) объект аутентификации.
Разве Room не доверяет мне? В какой-то степени да, в какой-то степени нет.
Это потому, что я не позволил Room автоматически генерировать первичный ключ и, следовательно, Room и компилятор не могут поверить, что я не буду дублировать первичные ключи?
Нет. Ваш код работает нормально и допускает уникальность, когда он предоставляется.
Или я что-то упускаю? Как объяснено выше, я считаю, что это так. Опять же, с уникальными значениями для system_id, код работает нормально (предполагается, что других сущностей нет).
Рассмотрим следующую полосу -
- добавление
@Query("SELECT * FROM authentication")
fun getAllAuth(): List<Authentication>
в AuthDao - удаление приостановить , чтобы разрешить запуск из основного потока (для удобства)
использует ваш код: -
val authDatabase = Room.databaseBuilder(this,AuthDatabase::class.java,"authdb")
.allowMainThreadQueries()
.build()
var a1 = Authentication("system_id1","password","www.server.etc")
var a2 = Authentication("system_id2","password","xxx.server.etc")
Log.d("AUTHINSERT","Insert of Authentication returned " + authDatabase.authDao().insertAuth(a1))
Log.d("AUTHINSERT","Insert of Authentication returned " + authDatabase.authDao().insertAuth(a2))
Log.d("AUTHINSERT","Insert of Authentication returned " + authDatabase.authDao().insertAuth(a1))
var authentications = authDatabase.authDao().getAllAuth()
for (authentication in authentications) {
Log.d("AUTHINFO",authentication.systemID)
}
Выполнение этого в первый раз приводит к журналу, содержащему: -
2020-01-09 16:39:58.351 D/AUTHINSERT: Insert of Authentication returned 1
2020-01-09 16:39:58.352 D/AUTHINSERT: Insert of Authentication returned 2
2020-01-09 16:39:58.354 D/AUTHINSERT: Insert of Authentication returned 3
2020-01-09 16:39:58.358 D/AUTHINFO: system_id2
2020-01-09 16:39:58.358 D/AUTHINFO: system_id1
То есть, кажется, три строки были вставлены, с rowid 1-3.
- rowid является обычно скрытая строка, которая имеет уникальное целое число (64-битное знаковое), предоставляемое SQLite sqlite (если только для rowid не задан псевдоним).
Однако были выведены только 2 объекта аутентификации. Это связано с тем, что строка с rowid 1 была удалена, а строка с rowid 3 была добавлена. Это то, что делает REPLACE.
Если приведенный выше код запускается снова, то результат будет: -
2020-01-09 16:44:25.455 D/AUTHINSERT: Insert of Authentication returned 4
2020-01-09 16:44:25.456 D/AUTHINSERT: Insert of Authentication returned 5
2020-01-09 16:44:25.458 D/AUTHINSERT: Insert of Authentication returned 6
2020-01-09 16:44:25.462 D/AUTHINFO: system_id2
2020-01-09 16:44:25.462 D/AUTHINFO: system_id1
То есть данные в базе данных были сохранены, и потому что данные в объектах (хотя они не совпадают с объектами, которые были бы собраны и удалены мусором) - то же самое. Две строки были удалены и добавлены новые строки (rowid 5 и 6 будут в базе данных).