簡體   English   中英

即使數據庫中存在匹配的行,Room SQLite查詢也不返回任何結果

[英]Room SQLite query doesn't return any results, even though there are rows in the database that match

我正在使用以下命令從Room數據庫獲取數據:

select * from location_search_results where searchQuery = "wilmington"

這是數據庫的樣子:

在此處輸入圖片說明

以下是搜索結果: 在此處輸入圖片說明

我已經驗證了該表的名稱正確無誤,並且沒有任何拼寫錯誤,因此為什么該查詢不返回應匹配的三行中的任何一行?

編輯代碼:

源代碼可在此處公開獲得,我正在mvvm分支中工作,因此,如果將其拉出,請確保已在此處。 以下是相關的類:

LocationSearchResponse.kt:

@Entity(tableName = "location_search_results")
class LocationSearchResponse(
        @ColumnInfo(name = "type")
        val type: String,
        @TypeConverters(DataConverter::class)
        @SerializedName("query")
        val searchQuery: List<String>,
        @TypeConverters(DataConverter::class)
        val features: List<Feature>,
        @ColumnInfo(name = "attribution")
        val attribution: String
) {
    @PrimaryKey(autoGenerate = true)
    var id: Int = 0
}

LocationSearchRepositoryImpl.kt:

class LocationSearchRepositoryImpl (
        private val locationResponseDao: LocationResponseDao,
        private val locationNetworkDataSource: LocationNetworkDataSource
): LocationSearchRepository {

    init {
        locationNetworkDataSource.downloadedLocationSearchResults.observeForever { locationResults ->
            persistFetchedLocations(locationResults)
        }
    }

    // update search data in db if necessary, then return the data that was searched for.
    override suspend fun searchForLocation(query: String): LiveData<out LocationSearchResponse> {
        return withContext(Dispatchers.IO) {
            initSearch(query)
            return@withContext locationResponseDao.searchForLocation(query)
        }
    }

    // if a fetch is necessary (query has not already been searched), fetch search results
    private suspend fun initSearch(query: String) {
        if (isFetchLocationResultsNeeded(query))
            fetchLocationResults(query)
    }

    private fun isFetchLocationResultsNeeded(query: String) : Boolean {
        // get the cached results.  If it's null, return true because it needs to be updated
        val cachedResults = locationResponseDao.searchForLocationNonLive(query.toLowerCase())

        if (cachedResults == null) return true

        // if the results are empty, it needs to be fetched, else it doesn't
        return cachedResults.features.isEmpty()
    }

    private suspend fun fetchLocationResults(query: String) {
        locationNetworkDataSource.fetchLocationSearchResults("mapbox.places", query)
    }

    private fun persistFetchedLocations(fetchedLocationResults: LocationSearchResponse) {
        GlobalScope.launch(Dispatchers.IO) {
            locationResponseDao.upsert(fetchedLocationResults)
        }
    }
}

LocationResponseDao.kt:

@Dao
interface LocationResponseDao {

    // update or insert existing entry if there is a conflict when adding to db
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun upsert(locationResults: LocationSearchResponse)

    @Query("select * from location_search_results WHERE searchQuery = :query")
    fun searchForLocation(query: String): LiveData<LocationSearchResponse>

    @Query("select * from location_search_results WHERE searchQuery = :query")
    fun searchForLocationNonLive(query: String): LocationSearchResponse?

    @Query("delete from location_search_results")
    fun nukeTable()
}

和ChooseCityFragment.kt:

class ChooseCityFragment : ScopedFragment(), KodeinAware {

    override val kodein by closestKodein()
    private val locationViewModelFactory: LocationResponseViewModelFactory by instance()
    private val weatherResponseViewModelFactory: WeatherResponseViewModelFactory by instance()

    private lateinit var locationViewModel: LocationResponseViewModel
    private lateinit var weatherViewModel: WeatherResponseViewModel

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {

        setupViews()

        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.choose_city_fragment, container, false)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        locationViewModel = ViewModelProviders.of(this, locationViewModelFactory)
                .get(LocationResponseViewModel::class.java)

        weatherViewModel = ViewModelProviders.of(this, weatherResponseViewModelFactory)
                .get(WeatherResponseViewModel::class.java)

        updateToolbar()
    }

    fun updateToolbar() {
        (activity as? AppCompatActivity)?.supportActionBar?.title = "Choose Location"
        (activity as? AppCompatActivity)?.supportActionBar?.subtitle = null
    }

    fun bindUI() = launch {
        val locationResults = locationViewModel.locationResponse
        val owner = viewLifecycleOwner

        locationResults.observe(owner, Observer {
            if (it == null) return@Observer

            // TODO: set loading icon to GONE

            initRecyclerView(it.features.toLocationSearchResultListItem())
        })
    }

    fun setupViews() = launch {
        search_button.setOnClickListener {
            searchLocations()
            search_results_rv.adapter?.notifyDataSetChanged()
        }
    }

    // TODO: search text can not be more than 20 words or more than 256 characters.  Need to account for this
    fun searchLocations() = launch {
        val searchText = search_box.text.toString()

        if (searchText != "") {
            locationViewModel.searchLocation(search_box.text.toString())
            bindUI()
        } else
            Toast.makeText(context?.applicationContext, "Please enter a search term", Toast.LENGTH_SHORT).show()
    }

    private fun List<Feature>.toLocationSearchResultListItem() : List<LocationSearchResultListItem> {
        return this.map {
            LocationSearchResultListItem(it)
        }
    }

    private fun initRecyclerView(items: List<LocationSearchResultListItem>) {
        val groupAdapter = GroupAdapter<ViewHolder>().apply {
            addAll(items)
        }

        groupAdapter.notifyDataSetChanged()

        search_results_rv.apply {
            layoutManager = LinearLayoutManager(this@ChooseCityFragment.context)
            adapter = groupAdapter
        }

        groupAdapter.setOnItemClickListener { item, view ->
            (item as? LocationSearchResultListItem)?.let {
                refreshWeather(it.feature.coordinates[0], it.feature.coordinates[1])
            }
        }
    }

    private fun refreshWeather(latitude: Double, longitude: Double) = launch {
        weatherViewModel.refreshWeatherWithCoordinates(latitude, longitude)
    }
}

嘗試這樣的事情
這是一個dao接口示例
在查詢中使用大寫字母

@Query("SELECT * FROM person WHERE favoriteColor LIKE :color")
List<Person> getAllPeopleWithFavoriteColor(String color);

更多信息在這里

事實證明,在searchQuery的末尾添加了一個我看不到的空格。 一旦確定了代碼在何處添加了該空間,便將其刪除,現在一切看起來都很好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM