Room with Flow возвращает значение null, когда оно пусто
Я только начал смотреть на Room, Coroutines и Flow и наткнулся на кое-что странное: то, что я ожидаю, будет пустым потоком, на самом деле имеет один нулевой элемент.
Моя настройка выглядит следующим образом: с общим T
для моих настоящих сущностей.
interface TDao {
@Query("SELECT * FROM Table WHERE date=:date")
fun getT(date: String): Flow<T>
}
@Singleton
class TRepository @Inject constructor(
private val apiService: TApiService,
private val Tdao: TDao
) {
suspend fun getTFor(date: String): Flow<T> =
Tdao
.getT(date)
.map {
if (it == null) {
returnTFromDatabase()
} else {
it
}
}
Теперь, когда в базе данных нет T
в нем для date
, Я ожидаю, что он вернет пустой поток без элементов. Вместо этого у него есть одинnull
элемент, которого никогда не должно быть, потому что T
не допускает значения NULL.
Я написал для него такой тест:
@RunWith(AndroidJUnit4::class)
class TDatabaseTest {
private lateinit var db: TDatabase
private lateinit var underTest: TDao
@Before
fun setUp() {
val context = InstrumentationRegistry.getInstrumentation().context
db = Room.inMemoryDatabaseBuilder(context, TDatabase::class.java).build()
underTest = db.TDao()
}
@After
fun tearDown() {
db.close()
}
@Test
fun givenEmptyDatabase_thenHasNoItems() {
runBlocking {
val list = underTest.getT("1999").take(1).toList()
assertEquals(1, list.size)
}
}
}
... и это проходит, потому что снова есть один null
товар возвращен.
Что мне не хватает? Что здесь не так, потому что я не могу понять. Почему я получаю один нулевой элемент в потоке с элементами, не допускающими значения NULL?
1 ответ
Как Room обрабатывает допустимость значений NULL, зависит от того, как вы определяете тип возвращаемого значения функции запроса. Документы говорят:
- Когда тип возврата
Flow<T>
при запросе пустой таблицы возникает исключение с нулевым указателем.- Когда тип возврата
Flow<T?>
при запросе пустой таблицы выдаетсяnull
значение.- Когда тип возврата
Flow<List<T>>
при запросе пустой таблицы создается пустой список.
В приведенном выше фрагменте обсуждаются пустые таблицы, но я предполагаю, что такое же поведение применимо к любому запросу, который не возвращает строк.
Источник: Документы по помещению по запросу.
Room - это база данных, написанная на Java, и поэтому она игнорирует Kotlin optional. Я предлагаю всегда объявлять тип возврата запроса или, в вашем случае,Flow<T?>
тип, необязательный. Если вам не нужен нулевой тип в потоке, вы можете использоватьfilterNotNull()
работают так:
Tdao.getT(date).filterNotNull()