Android Room : Each bind variable in the query must have a matching method

Gaurav Vashisth picture Gaurav Vashisth · May 26, 2017 · Viewed 7.5k times · Source

I am using the android persistence library Room with kotlin.

The Dao looks like this

@Dao
interface CountryDao {
    @Query("SELECT * FROM countries")
    fun loadAllCountried() : LiveData<List<CountryEntity>>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertAll(products: List<CountryEntity>)

    @Query("SELECT * FROM countries WHERE id = :countryId")
    fun loadCountry(countryId: Int): LiveData<CountryEntity>

    @Query("SELECT * FROM countries WHERE id = :countryId")
    fun loadCountrySync(countryId: Int): CountryEntity

}

It seems good to me but I am getting this error

Error: Each bind variable in the query must have a matching method parameter. Cannot find method parameters for :countryId.

I can see the parameter is named as countryId, so what may be the issue?

FYI: Here is the generate code in CountryDao_Impl.java

@Override
public CountryEntity loadCountrySync(int arg0) {
  final String _sql = "SELECT * FROM countries WHERE id = ?";
  final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 1);
  int _argIndex = 1;
  final Cursor _cursor = __db.query(_statement);
  try {
    final int _cursorIndexOfId = _cursor.getColumnIndexOrThrow("id");
    final int _cursorIndexOfPopulation = _cursor.getColumnIndexOrThrow("population");
    final CountryEntity _result;
   if(_cursor.moveToFirst()) {
     _result = new CountryEntity();
      final int _tmpId;
      _tmpId = _cursor.getInt(_cursorIndexOfId);
      _result.setId(_tmpId);
      final long _tmpPopulation;
      _tmpPopulation = _cursor.getLong(_cursorIndexOfPopulation);
      _result.setPopulation(_tmpPopulation);
    } else {
      _result = null;
    }
    return _result;
  } finally {
    _cursor.close();
    _statement.release();
  }
}

In this method I see arg0 is not being used anywhere in the method.

EDIT: This seems to be fixed in the new plugins. Several of the answers here are correct, but I can't accept every answer, Sorry.

Answer

Tom Insam picture Tom Insam · May 27, 2017

Kotlin isn't preserving the names of the arguments properly - this is https://youtrack.jetbrains.com/issue/KT-17959

You can work around this by using :arg0, :arg1, etc, as parameter names in your @Query statements:

@Query("SELECT * FROM countries WHERE id = :arg0")
fun loadCountry(countryId: Int): LiveData<CountryEntity>

@Query("SELECT * FROM countries WHERE id = :arg0")
fun loadCountrySync(countryId: Int): CountryEntity