'Query method parameters should either be a type that can be converted into a database column or a List

package com.example.hand.data;
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.TypeConverters;
import androidx.room.Update;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Dao
@TypeConverters(dateConverter.class)
public interface salaryDao
{
    @Insert
    void insertSal(salary sal);
    @Update
    void updateSal(salary sal);
    @Delete
    void deleteSal(salary sal);


    @Query("select * from salary order by id asc")
    LiveData<List<salary>> selectSal(salary...sal);
    @Query("select * from salary where time>=:from and time<=:to order by time ")
    LiveData<List<salary>> selectByDate(Date from,Date to);
    @Query("select * from salary where idCar=:id order by time asc ")
    LiveData<List<salary>> selectByDate(Long id);
    @Query("select sum(amount) from salary where idCar=:id order by time asc ")
    double getSum(long id);

}

the error

C:\Users\MCD\AndroidStudioProjects\Hand\app\src\main\java\com\example\hand\data\salaryDao.java:30: error: Query method parameters should either be a type that can be converted into a database column or a List / Array that contains such type. You can consider adding a Type Adapter for this. LiveData<List> selectSal(salary...sal);



Solution 1:[1]

You have a few issues with:-

@Query("select * from salary order by id asc")
LiveData<List<salary>> selectSal(salary...sal)

The query is saying SELECT every row. It is not saying SELECT some rows according to a parameter. Whilst the function is saying to utilise the passed parameter. Room doesn't know what to do with salary...sal nor would it be able to handle it as it does not equate to something that it can place into the query (a column's value or a list of column values).

So you need to define/use a query that will SELECT certain rows and typically this would be via a WHERE clause.

You appear to want to select a subset of Salaries based upon a list of salary objects. However, a salary, as per the message, is NOT suitable for a query parameter.

I suspect that you want something like:-

@Query("select * from salary WHERE id IN(:salary_id_list) order by id asc")
LiveData<List<Salary>> selectSal(long[] salary_id_list);

So the query is saying SELECT only those rows WHERE the salary's id is in the provided list. The provided list would be something like 10,20,30 (i.e. the id of the respective salaries).

Working Demo

The Salary class @Entity based upon what can be extracted from the code you have provided (so will very likely NOT match your salary class) :-

@Entity
class Salary {
    @PrimaryKey
    Long id=null;
    Date time;
    double amount;
    long idCar;

    /* ADDED for the DEMO*/
    public static long[] getSalaryIdList(Salary...salaries) {
        long[] rv = new long[salaries.length];
        int i = 0;
        for (Salary s: salaries) {
            rv[i++] = s.id;
        }
        return rv;
    }
}
  • Note the added method to extract an array (long[]) of id's from the passed Salaries.

SalaryDao

@Dao
public interface SalaryDao
{
 @Insert
 long insertSal(Salary sal); //<<<<<<<<<< CHANGED
 @Update
 void updateSal(Salary sal);
 @Delete
 void deleteSal(Salary sal);


 /*<<<<<<<<<< CHANGED >>>>>>>>>>*/
 @Query("select * from salary WHERE id IN(:salary_id_list) order by id asc")
 List<Salary> selectSal(long[] salary_id_list);

 @Query("select * from salary where time>=:from and time<=:to order by time ")
 List<Salary> selectByDate(Date from, Date to);

 @Query("select * from salary where idCar=:id order by time asc ")
 List<Salary> selectByDate(Long id);
 @Query("select sum(amount) from salary where idCar=:id order by time asc ")
 double getSum(long id);

}
  • Note that for brevity/convenience LiveData has not bee used

The DateConverter class (assumed converter Date to/from long) :-

public class DateConverter {

   @TypeConverter
   public long fromDateToLong(Date date) {
      return date.getTime();
   }

   @TypeConverter
   public Date fromLongToDate(long date) {
      return new Date(date);
   }
}
  • Note @TypeConverters annotation moved to @Database for full scope.

An @Database annotated class, to cater for the demo:-

@TypeConverters({DateConverter.class})
@Database(entities = {Salary.class}, version = 1, exportSchema = false)
abstract class TheDatabase extends RoomDatabase {
   abstract SalaryDao getSalaryDao();

   private static TheDatabase instance = null;
   static TheDatabase getInstance(Context context) {
      if (instance == null) {
         instance = Room.databaseBuilder(context,TheDatabase.class,"the_database.db")
                 .allowMainThreadQueries()
                 .build();
      }
      return instance;
   }
}
  • note allowMainThreadQueries used for brevity/convenience

Finally putting it all together into a demo that adds 5 Salaries and the uses the selectSal dao method to retrieve a subset of the 5 Salaries (1st,3rd and 5th):-

public class MainActivity extends AppCompatActivity {

    TheDatabase db;
    SalaryDao dao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        db = TheDatabase.getInstance(this);
        dao = db.getSalaryDao();

        Salary s1 = new Salary();
        s1.amount = 100;
        s1.idCar = 10;
        s1.time = new Date();
        s1.id = dao.insertSal(s1);

        Salary s2 = new Salary();
        s2.amount = 200;
        s2.idCar = 20;
        s2.time = new Date();
        s2.id = dao.insertSal(s2);

        Salary s3 = new Salary();
        s3.amount = 300;
        s3.idCar = 30;
        s3.time = new Date();
        s3.id = dao.insertSal(s3);

        Salary s4 = new Salary();
        s4.amount = 400;
        s4.idCar = 40;
        s4.time = new Date();
        s4.id = dao.insertSal(s4);

        Salary s5 = new Salary();
        s5.amount = 500;
        s5.idCar = 50;
        s5.time = new Date();
        s5.id = dao.insertSal(s5);

        for(Salary s: dao.selectSal(Salary.getSalaryIdList(s1,s3,s5))) {
            Log.d("DBINFO","Salary ID is " + s.id + " Amount is $" + s.amount + " IdCar is " + s.idCar + " Time is " + s.time);
        }
    }
}
  • Note this is intended to just run the once (although will subsequently run but additional rows will be added each time).

The resultant output (for the first run) written to the log :-

2022-05-14 12:55:41.015 D/DBINFO: Salary ID is 1 Amount is $100.0 IdCar is 10 Time is Sat May 14 12:55:40 GMT+10:00 2022
2022-05-14 12:55:41.015 D/DBINFO: Salary ID is 3 Amount is $300.0 IdCar is 30 Time is Sat May 14 12:55:40 GMT+10:00 2022
2022-05-14 12:55:41.015 D/DBINFO: Salary ID is 5 Amount is $500.0 IdCar is 50 Time is Sat May 14 12:55:40 GMT+10:00 2022
  • i.e. 1st, 3rd and 5th have been retrieved.

The database via AppInspection :-

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 MikeT