Комната: Как выполнить запрос на основе составных первичных ключей?

Возможен ли запрос с использованием составного первичного ключа с помощью Room?

@Entity(
    tableName = "market_cap",
    primaryKeys = ["assetId", "timestamp"]
)
data class MarketCapDataEntity(
    val assetId: String,
    val timestamp: Long,
    val price: Double
)

Допустим, я хочу выполнить запрос по первичному ключу, как показано ниже?

@Query("SELECT * FROM market_cap WHERE primaryKeys = :compositeKey")
suspend fun getMarketCapByAssetId(compositeKey: String): List<MarketCapDataEntity>
0
0
63
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вам необходимо указать каждый компонент первичного ключа в вашем SQL-запросе, а не пытаться использовать один составной ключ.

@Entity(
    tableName = "market_cap",
    primaryKeys = ["assetId", "timestamp"]
)
data class MarketCapDataEntity(
    val assetId: String,
    val timestamp: Long,
    val price: Double
)

@Dao
interface MarketCapDao {
    @Query("SELECT * FROM market_cap WHERE assetId = :assetId AND timestamp = :timestamp")
    suspend fun getMarketCapByAssetIdAndTimestamp(assetId: String, timestamp: Long): MarketCapDataEntity?
}

Я понимаю, но неужели для primaryKeys нет специального свойства?

Bitwise DEVS 16.04.2024 03:19

В Room нет специального свойства или параметра, который можно использовать для прямого указания составных первичных ключей как единого объекта в запросах. Каждый компонент составного первичного ключа необходимо указывать в SQL-запросе индивидуально.

Yakubu 16.04.2024 12:16
Ответ принят как подходящий

Возможен ли запрос с использованием составного первичного ключа с помощью Room?

Нет (см. ниже), НО это то, что вы могли бы/не могли бы запросить.

По сути, цель индекса состоит в том, чтобы базовая система (оптимизатор запросов) оптимально выполняла поиск в базе данных.

Таким образом, вы никогда не запрашиваете индекс по индексу, а по столбцам, которые могут или не могут быть частью индекса.

Таким образом, для @Query вы просто указываете столбец(и) для запроса. Не существует единого представления составного индекса, которое можно было бы использовать.

Таким образом, @Query("SELECT * FROM market_cap WHERE primaryKeys = :compositeKey") приведет к ошибке, поскольку PrimaryKeys будет считаться именем столбца, которого не существует.

Вместо этого вы должны использовать что-то вроде: -

@Query("SELECT * FROM market_cap WHERE assetId = :assetId AND timestamp = :timestamp")
  • очень вероятно, что для поиска по таблице будет использоваться индекс первичного ключа (обычно решает оптимизатор запроса)
    • однако ВСЕГДА (для Room) будет другой скрытый/невидимый индекс, основанный на обычно скрытом столбце rowid (все таблицы Room, определенные с помощью аннотации @Entity, будут таблицами ROWID). В некоторых случаях это вполне может быть оптимальным индексом, поскольку SQLite написан с учетом идентификатора строки, обработка которого может быть в два раза быстрее, чем других индексов. Вы можете найти https://sqlite.org/rowidtable.html полезным.

Удобная аннотация и первичный ключ(и)

Следует отметить, что некоторые удобные аннотации, например @Update и @Delete, действительно используют и требуют значений поля или полей, из которых состоит первичный ключ.

Поэтому, когда/если используется любой из них, важно, чтобы объект, переданный в аннотированную функцию/метод, имел значения полей первичного ключа, установленные в соответствующие значения (отмечая, что вы не можете обновлять значения первичного ключа, поскольку тогда это не позволит найти строку) .

  • Если вам нужно обойти ограничения/ограничения удобства, вы можете использовать аннотацию @Query с соответствующим SQL, например.

@Query("UPDATE market_cap SET assetId=:newAssetId, timestamp=:newTimeStamp WHERE assetId=:originalAssetId AND timestamp=originalTimeStamp")

  • очевидно, вы передаете две пары assetsId и Timestamp, как следует из названий параметров.

Другие вопросы по теме