问题描述
我将 Device 对象存储在 Room 数据库中,但在检索作为浮点数列表的属性 (temp_values) 之一时遇到问题.我遵循了here上的其他建议,说明您需要一个类型转换器,所以我在这里展示了这一点.当我尝试编译时出现此错误:
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:
"警告:查询返回一些列 [temp_values],这些列不是由 java.lang.Float 使用.您可以在字段来指定映射.您可以通过以下方式抑制此警告用@SuppressWarnings(RoomWarnings.CURSOR_MISMATCH).返回的列查询:temp_values.java.lang.Float 中的字段:."
问题在于 DAO 中的 getTempValues 查询,如果我将其注释掉,那么一切都可以正常编译.我在 Device 对象、TemperatureListConverter 和我的 DAO 下面包含了.
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);
}
我在这里添加了我的数据库类.
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();
}
}
推荐答案
当 Room 处理返回集合类型(在本例中为List
)的查询时,它会尝试生成一个实现对于返回表的多行的查询.这是典型用途,如在您的查询中获取所有设备:
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();
当在查询中使用返回集合的 TypeConverter
以生成单行时,您需要给 Room 一个您想要的提示.一种方法是将集合值包装在一个类中:
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.
这篇关于如何存储 List<Object>在房间数据库中?(我在使用 DAO 查询检索列表时遇到问题)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!