简体   繁体   English

即使数据库中存在匹配的行,Room SQLite查询也不返回任何结果

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

I am using this command to get data from a Room database: 我正在使用以下命令从Room数据库获取数据:

select * from location_search_results where searchQuery = "wilmington"

Here is what the database looks like: 这是数据库的样子:

在此处输入图片说明

And here are the search results: 以下是搜索结果: 在此处输入图片说明

I have verified that the name of the table is correct and everything, and there's no spelling errors that I can find, so why would this query not return any of the three rows that it should match? 我已经验证了该表的名称正确无误,并且没有任何拼写错误,因此为什么该查询不返回应匹配的三行中的任何一行?

EDIT for code: 编辑代码:

The source code is publicly available here , I am working in the mvvm branch, so if you pull it, make sure you're there. 源代码可在此处公开获得,我正在mvvm分支中工作,因此,如果将其拉出,请确保已在此处。 Below are the relevant classes: 以下是相关的类:

LocationSearchResponse.kt: 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: 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: 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()
}

and ChooseCityFragment.kt: 和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)
    }
}

try something like this 尝试这样的事情
it`sa dao interface example 这是一个dao接口示例
use big letters in your query 在查询中使用大写字母

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

more info here 更多信息在这里

It turns out there was a space being added to the end of the searchQuery that I wasn't able to see. 事实证明,在searchQuery的末尾添加了一个我看不到的空格。 Once I figured out where my code was adding that space, I removed it and now everything looks good. 一旦确定了代码在何处添加了该空间,便将其删除,现在一切看起来都很好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM