【问题标题】:How to store List<Object> in Room database? (I'm having trouble retrieving the list with DAO query)如何将 List<Object> 存储在 Room 数据库中? (我在使用 DAO 查询检索列表时遇到问题)
【发布时间】:2020-06-08 17:59:06
【问题描述】:

我将 Device 对象存储在 Room 数据库中,但在检索作为浮点列表的属性 (temp_values) 之一时遇到问题。我遵循了其他在这里找到的建议,说你需要一个类型转换器,所以我在这里展示了。当我尝试编译时出现此错误:

"警告:查询返回的一些列 [temp_values] 不是 由 java.lang.Float 使用。您可以在 字段来指定映射。您可以通过以下方式抑制此警告 用注释方法 @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH)。返回的列 查询:temp_values。 java.lang.Float 中的字段:."

问题在于 DAO 中的 getTempValues 查询,如果我将其注释掉,那么一切都可以正常编译。我在 Device 对象、TemperatureListConverter 和我的 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);
}

编辑:我在这里添加了我的数据库类。

@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();
    }
}

【问题讨论】:

  • 能否请您在扩展 RoomDatabase 的位置发布您的课程?
  • @Swayangjit 添加了!

标签: java android-room


【解决方案1】:

当 Room 处理返回集合类型的查询(本例中为 List&lt;Float&gt;)时,它会尝试为返回表的多行的查询生成实现。这是典型的用途,如在查询中获取所有设备:

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

当一个返回集合的TypeConverter 用于旨在产生单行的查询中时,您需要向 Room 提示您想要什么。一种方法是将集合值包装在一个类中:

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

并更改查询以返回包装类:

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

我用你发布的代码试过这个。它消除了构建错误并似乎生成了所需的实现代码。

【讨论】:

    【解决方案2】:

    转换泛型类型库时似乎存在一些问题。试试下面的

    @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);
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-17
      • 2022-12-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-24
      • 1970-01-01
      • 2021-06-25
      相关资源
      最近更新 更多