How to store List<Object> in Room database? (I'm having trouble retrieving the list with DAO query)

五迷三道 提交于 2021-01-28 05:23:39

问题


I am storing Device objects in a Room database and I'm having a problem with retrieving one of the attributes (temp_values) that is a list of floats. I've followed other advice found on here that says you need a type converter so I've shown that here. When I try to compile I get this error:

"warning: The query returns some columns [temp_values] which are not used by java.lang.Float. You can use @ColumnInfo annotation on the fields to specify the mapping. You can suppress this warning by annotating the method with @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH). Columns returned by the query: temp_values. Fields in java.lang.Float: ."

The issue is with the getTempValues query in the DAO, if I comment this out then everything compiles fine. I've included below the Device object, the TemperatureListConverter, and my DAO.

@Entity(tableName = "devices")
@TypeConverters(TemperatureListConverter.class)
public class Device implements Serializable {

    @PrimaryKey
    @NonNull
    @ColumnInfo(name = "serial_num")
    private String serialNum;

    @ColumnInfo(name = "temp_values")
    @TypeConverters(TemperatureListConverter.class)
    private List<Float> tempValues;

    public Device(String serialNum) {
        this.serialNum = serialNum;
        this.tempValues = new ArrayList<>();
    }

    public String getSerialNum() {
        return serialNum;
    }

    public List<Float> getTempValues() { 
        return tempValues; 
    }

    public void setTempValues(List<Float> tempValues) {
        this.tempValues = tempValues;
    }
}
public class TemperatureListConverter {

    private static final Gson gson = new Gson();

    @TypeConverter
    public static List<Float> toTempList(String tempValuesString) {
        if (tempValuesString == null) {
            return Collections.emptyList();
        }

        Type type = new TypeToken<List<Float>>() {}.getType();
        return gson.fromJson(tempValuesString, type);
    }

    @TypeConverter
    public static String fromTempList(List<Float> tempValues) {
        return gson.toJson(tempValues);
    }
}
@Dao
@TypeConverters(TemperatureListConverter.class)
public interface DeviceDao {
    @Query("SELECT * FROM devices")
    List<Device> getAllDevices();

    @Query("SELECT * FROM devices WHERE serial_num = :serialNum")
    Device getDevice(String serialNum);

    @Query("SELECT temp_values FROM devices WHERE serial_num = :serialNum")
    List<Float> getTempValues(String serialNum);

    @Query("UPDATE devices SET temp_values = :tempValues WHERE serial_num = :serialNum")
    int setTempValues(String serialNum, List<Float> tempValues);

    @Insert
    void insert(Device... device);

    @Query("DELETE FROM devices WHERE serial_num = :serialNum")
    void deleteBySerial(String serialNum);
}

EDIT: I've added my database class here.

@Database(entities = {Device.class}, version = 37, exportSchema = false)
@TypeConverters(TemperatureListConverter.class)
public abstract class DeviceDatabase extends RoomDatabase {

    private static final String DB_NAME = "devices_db";
    private static DeviceDatabase deviceDb;

    // simple singleton
    public static DeviceDatabase getDeviceDb(Context context) {
        if (deviceDb == null) {
            deviceDb = Room.databaseBuilder(context, DeviceDatabase.class, DB_NAME)
                    .fallbackToDestructiveMigration()
                    .build();
        }

        return deviceDb;
    }

    public abstract DeviceDao getDeviceDao();

    public void addDevice(final Device device) {

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    getDeviceDao().insert(device);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    public void removeDevice(final String serialNum) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    getDeviceDao().deleteBySerial(serialNum);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    public Device getDevice(final String serialNum) {
        final Device[] finalDevice = new Device[1];

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    finalDevice[0] = getDeviceDao().getDevice(serialNum);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        thread.start();

        try {
            thread.join();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return finalDevice[0];
    }

    public List<Float> getTempValues(final String serialNum) {
        final List<Float> finalTempValues = new ArrayList<>();

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                 finalTempValues.addAll(getDeviceDao().getTempValues(serialNum));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        thread.start();

        try {
            thread.join();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return finalTempValues;
    }

    public void setTempValues(final String serialNum, final List<Float> 
                                tempValues) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    getDeviceDao().setTempValues(serialNum, tempValues);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

回答1:


When Room processes a query that returns a collection type (List<Float> in this case), it tries to generate an implementation for a query that returns multiple rows of the table. That is the typical use, as in your query to get all devices:

@Query("SELECT * FROM devices")
List<Device> getAllDevices();

When a TypeConverter that returns a collection is used in a query intended to yield a single row, you need to give Room a hint of what you want. One way to do that is to wrap the collection value in a class:

public class ListWrapper {
    @ColumnInfo(name = "temp_values")
    List<Float> tempValues;
}

And change the query to return the wrapper class:

@Query("SELECT temp_values FROM devices WHERE serial_num = :serialNum LIMIT 1")
ListWrapper getTempValues(String serialNum);

I tried this with the code you posted. It eliminates the build error and appears to produce the desired implementation code.




回答2:


It seems there is some issue while converting a generic type base. Try the following

@TypeConverter
    public static List<Float> toTempList(String tempValuesString) {
        if (tempValuesString == null) {
            return Collections.emptyList();
        }

        Type type = new TypeToken<List<Float>>() {}.getType();
        return gson.fromJson(tempValuesString, type);
    }

    @TypeConverter
    public static String fromTempList(List<Float> tempValues) {
        Type type = new TypeToken<List<Float>>() {}.getType();
        return gson.toJson(tempValues, type);
    }


来源:https://stackoverflow.com/questions/62268373/how-to-store-listobject-in-room-database-im-having-trouble-retrieving-the-l

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!