Жесткий логический запрос в базе данных комнаты

Я создаю приложение для Android, которое отображает список потенциальных совпадений для пользователя. Пользователь может щелкнуть по одному из них, чтобы поставить лайк пользователю, и я сохраняю все эти лайки локально.

Я могу написать запрос, чтобы получить список таких совпадений:

@Query("SELECT * FROM match WHERE liked = :liked ORDER BY match DESC LIMIT :limit")
fun getMatches(limit: Int = 6, liked: Boolean = true): Flowable<List<Match>>

Я узнал, что это нормально работает. Однако я не предвижу никакого сценария, в котором я когда-либо установил бы liked в значение false, и поэтому мне любопытно, есть ли способ жестко закодировать мое логическое условие? Если я попробую:

@Query("SELECT * FROM match WHERE liked = true ORDER BY match DESC LIMIT :limit")

Во время компиляции я получаю следующую ошибку:

Error:(8, 0) Gradle: error: There is a problem with the query: [SQLITE_ERROR] SQL error or missing database (no such column: true)

Как я могу жестко закодировать это логическое значение в строке запроса?

Я также пробовал:

  • Wrapping the condition in single quotes
    • @Query("SELECT * FROM match WHERE liked = 'true' ORDER BY match DESC LIMIT :limit")

person AdamMc331    schedule 09.12.2017    source источник


Ответы (3)


SQLite не имеет логического типа данных. Room сопоставляет его с INTEGER столбцом, сопоставляя true с 1 и false с 0.

Итак, я ожидал, что это сработает:

@Query("SELECT * FROM match WHERE liked = 1 ORDER BY match DESC LIMIT :limit")

Имейте в виду, что это поведение не задокументировано. Однако это не должно измениться, по крайней мере, без звуковых сигналов тревоги, поскольку нам нужно будет использовать миграции, чтобы иметь дело с любыми изменениями.

person CommonsWare    schedule 09.12.2017
comment
Это сработало, спасибо! Я определенно думаю, что это было упущено в документации Room. - person AdamMc331; 09.12.2017
comment
@ AdamMc331: В частности, после последнего раунда изменений, я бы сказал, что документация Room была пропущена в документации Room. :-( Но я рада, что у вас работает! - person CommonsWare; 09.12.2017
comment
Что ж, я дошел до этого! :П - person AdamMc331; 09.12.2017
comment
Ах да, документация по Room очень скудная ... спасибо! - person techfly; 16.02.2018
comment
База данных комнат явно генерирует 1 для True и 1 для False, поэтому мои запросы возвращают нулевые или пустые списки. В чем может быть проблема? - person TheRealChx101; 15.10.2019
comment
@ TheRealChx101: я рекомендую задать отдельный вопрос о переполнении стека, где вы предоставите минимальный воспроизводимый пример, демонстрирующий вашу проблему и ваши симптомы. . - person CommonsWare; 15.10.2019
comment
Спасибо. Итак, я смог вытащить файл базы данных с устройства, и после проверки в базе данных не было записей. У меня есть MediatorLiveData, который я использую для объединения сетевых и автономных (кэшированных) элементов. Каким-то образом моя реализация не сохраняется в базе данных, а переходит прямо в представление модели. Я могу решить эту проблему, но можете ли вы порекомендовать хороший способ, когда и как синхронизировать элементы с помощью MediatorLiveData или Transformations? - person TheRealChx101; 15.10.2019
comment
@ TheRealChx101: еще раз рекомендую задать отдельный вопрос о переполнении стека, где вы предоставите минимальный воспроизводимый пример, демонстрирующий вашу проблему. и ваши симптомы. - person CommonsWare; 15.10.2019

Подход CommonWare действительно работает, а также напрямую отвечает на вопрос OP; однако я не поклонник подобных предположений о базе данных. Предположение должно быть безопасным, но оно может создать неожиданную работу в будущем, если Room когда-либо решит изменить свою логическую реализацию.

Я бы посоветовал лучше не закодировать в запросе логическое значение 1 или 0. Если база данных находится за репозиторием, репозиторий все еще может предоставить изящный API. Лично я считаю, что защита большей кодовой базы от реализации базы данных в любом случае - это хорошо.

Метод Дао (скопировано из вопроса OP)

@Query("SELECT * FROM match WHERE liked = :liked ORDER BY match DESC LIMIT :limit")
fun getMatches(limit: Int = 6, liked: Boolean = true): Flowable<List<Match>>

Репозиторий

class Repository {
    public Flowable<List<Match>> getLikedMatches() {
        return dao.getMatches(6, true);
    }
}

Конечно, это вариант самоуверенный, поскольку предполагает определенный архитектурный стиль. Однако он не делает предположений о внутренней базе данных. Даже если репозиторий не защищает базу данных, вызов может быть выполнен в базе данных, передав значение true везде - также без каких-либо предположений относительно базовых данных.

person methodsignature    schedule 09.01.2018
comment
Если вы используете другой архитектурный стиль. вы можете защитить значение по умолчанию непосредственно в определении DAO. но вам нужно определить DAO как абстрактный класс, а не как интерфейс. То же определение, что и выше: @Query("SELECT * FROM match WHERE liked = :liked ORDER BY match DESC LIMIT :limit") protected abstract fun getMatches(limit: Int, liked: Boolean): Flowable<List<Match>> и общедоступная версия fun getLikedMatches(limit: Int = 6) = getMatches(limit, true) - person Almighty; 13.05.2019
comment
если Room когда-либо решит изменить свою логическую реализацию - они не должны этого делать, потому что все могут повредить существующие логические данные при обновлении Room. Я никогда не видел логики переноса данных для изменений библиотеки Room. - person The incredible Jan; 06.01.2021
comment
они не должны этого делать - они могут. они могут делать это медленно, но могут. Опасно полагаться на базовую реализацию Room. То, что что-то открыто, не является достаточным оправданием для его использования, особенно когда того же результата можно добиться с помощью задокументированного поведения. - person methodsignature; 17.01.2021
comment
они могут, но это было бы ошибкой. Я тоже умею кодировать ошибки, но, что удивительно, никому это не нравится. - person The incredible Jan; 17.05.2021

Вам не нужно сравнивать логический столбец со значением. Просто используйте само значение столбца как логическое выражение. Вы можете легко изменить свой запрос на SELECT * FROM match WHERE liked ORDER BY match DESC LIMIT :limit. Если вы хотите сравнить со значением false, вы можете использовать следующее выражение: where not liked.

person d.aemon    schedule 20.03.2020