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()
Другие вопросы по тегам