Android会议室数据库:如何处理实体中的Arraylist?

Tus*_*gna 49 java android android-room

我刚刚实施了Room以进行离线数据保存.但在Entity类中,我收到以下错误:

Error:(27, 30) error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
Run Code Online (Sandbox Code Playgroud)

课程如下:

@Entity(tableName = "firstPageData")
public class MainActivityData {
@PrimaryKey
private String userId;

@ColumnInfo(name = "item1_id")
private String itemOneId;

@ColumnInfo(name = "item2_id")
private String itemTwoId;

   // THIS IS CAUSING THE ERROR... BASICALLY IT ISN'T READING ARRAYS
   @ColumnInfo(name = "mylist_array")
    private ArrayList<MyListItems> myListItems;

public String getUserId() {
    return userId;
}

public void setUserId(String userId) {
    this.userId = userId;
}


public ArrayList<MyListItems> getMyListItems() {
    return myListItems;
}

public void setCheckListItems(ArrayList<MyListItems> myListItems) {
    this.myListItems = myListItems;
}
}
Run Code Online (Sandbox Code Playgroud)

所以基本上我想将ArrayList保存在数据库中,但我无法找到与之相关的任何内容.你可以指导我如何使用房间保存阵列吗?

注意:MyListItems Pojo类包含2个字符串(截至目前)

提前致谢.

Ami*_*ari 71

Type Converter专门为此而制造.在您的情况下,您可以使用下面给出的代码段将数据存储在DB中.

public class Converters {
@TypeConverter
public static ArrayList<String> fromString(String value) {
    Type listType = new TypeToken<ArrayList<String>>() {}.getType();
    return new Gson().fromJson(value, listType);
}

@TypeConverter
public static String fromArrayList(ArrayList<String> list) {
    Gson gson = new Gson();
    String json = gson.toJson(list);
    return json;
}
}
Run Code Online (Sandbox Code Playgroud)

并在你的房间DB中提到这个类

@Database (entities = {MainActivityData.class},version = 1)
@TypeConverters({Converters.class})
Run Code Online (Sandbox Code Playgroud)

更多信息在这里

  • 你如何从那个数组列表中查询? (3认同)
  • 谁能帮我在 Kotlin 中用 List 做同样的事情。在 Java 中它运行良好。但是当我在 Kolin 中转换它时它不起作用 (2认同)

Com*_*are 58

选项1:有MyListItems@Entity,因为MainActivityData是.MyListItems@ForeignKey回来的MainActivityData.但是,在这种情况下,MainActivityData不能private ArrayList<MyListItems> myListItems像在Room中一样,实体不会引用其他实体.但是,视图模型或类似的POJO构造可以具有a MainActivityData和它的关联ArrayList<MyListItems>.

选项#2:设置一对@TypeConverter方法来转换ArrayList<MyListItems>为某种基本类型(例如,String使用JSON作为存储格式).现在,MainActivityData可以ArrayList<MyListItems>直接拥有它.但是,没有单独的表格MyListItems,所以你不能很好地查询MyListItems.

  • 将来的某个时候,您可能需要查询商品,所以我通常会选择Option#1 (4认同)

Man*_*ddy 29

Kotlin版型转换器:

 class Converters {

    @TypeConverter
    fun listToJson(value: List<JobWorkHistory>?): String {

        return Gson().toJson(value)
    }

    @TypeConverter
    fun jsonToList(value: String): List<JobWorkHistory>? {

        val objects = Gson().fromJson(value, Array<JobWorkHistory>::class.java) as Array<JobWorkHistory>
        val list = objects.toList()
        return list
    }
}
Run Code Online (Sandbox Code Playgroud)

我将JobWorkHistory对象用于我的目的,使用你自己的对象

@Database(entities = arrayOf(JobDetailFile::class, JobResponse::class), version = 1)
@TypeConverters(Converters::class)
abstract class MyRoomDataBase : RoomDatabase() {
     abstract fun attachmentsDao(): AttachmentsDao
}
Run Code Online (Sandbox Code Playgroud)

  • 另外,您可能想从应用程序中的某个位置获取缓存的“Gson”实例。每次调用时初始化新的“Gson”实例可能会很昂贵。 (3认同)
  • 我认为与其反序列化为数组然后转换为List相比,不如使用以下List类型更好:val listType = object:TypeToken &lt;List &lt;JobWorkHistory &gt;&gt;(){} .type如下面的答案中提到的Amit。 (2认同)

Nit*_*sra 21

更好的List<String>转换器版本

class StringListConverter {
    @TypeConverter
    fun fromString(stringListString: String): List<String> {
        return stringListString.split(",").map { it }
    }

    @TypeConverter
    fun toString(stringList: List<String>): String {
        return stringList.joinToString(separator = ",")
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意使用“,”作为分隔符,因为有时您的字符串可能具有相同的字符,并且可能会很混乱。 (11认同)

can*_*ler 21

科特林答案

你需要做三件事:

  1. 创建转换器类。
  2. 在数据库上添加 Converters 类。
  3. 只需在实体类中定义您要使用的内容即可。

逐步使用示例:

步骤1 :

 class Converters {

    @TypeConverter
    fun listToJsonString(value: List<YourModel>?): String = Gson().toJson(value)

    @TypeConverter
    fun jsonStringToList(value: String) = Gson().fromJson(value, Array<YourModel>::class.java).toList()
}
Run Code Online (Sandbox Code Playgroud)

第2步 :

@Database(entities = [YourEntity::class], version = 1)
@TypeConverters(Converters::class)
abstract class YourDatabase : RoomDatabase() {
     abstract fun yourDao(): YourDao
}
Run Code Online (Sandbox Code Playgroud)

步骤3:

注意:您不需要调用Converter 的函数listToJsonString()jsonStringToList()他们在Room的后台使用。

@Entity(tableName = "example_database_table") 
data class YourEntity(
  @PrimaryKey(autoGenerate = true) val id: Long = 0,
  @ColumnInfo(name = "your_model_list") var yourModelList: List<YourModel>,
)
Run Code Online (Sandbox Code Playgroud)


Pat*_*ick 13

使用 Kotlin 的序列化组件 – kotlinx.serialization 的原生 Kotlin 版本

  1. 将 Kotlin 序列化 Gradle 插件和依赖项添加到您的build.gradle
apply plugin: 'kotlinx-serialization'

dependencies {
   ...
   implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1"
}
Run Code Online (Sandbox Code Playgroud)
  1. 将类型转换器添加到您的 Converter 类;
class Converters {
   @TypeConverter
   fun fromList(value : List<String>) = Json.encodeToString(value)

   @TypeConverter
   fun toList(value: String) = Json.decodeFromString<List<String>>(value)
}
Run Code Online (Sandbox Code Playgroud)
  1. 将您的 Converter 类添加到您的数据库类中:
@TypeConverters(Converters::class)
abstract class YourDatabase: RoomDatabase() {...}
Run Code Online (Sandbox Code Playgroud)

你完成了!

额外资源:

  • 您可能还需要 `classpath("org.jetbrains.kotlin:kotlin-serialization:$kotlinVersion")` (7认同)
  • 如果自动导入不起作用添加: import kotlinx.serialization.json.Json import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString (3认同)

小智 9

我个人建议不要使用@TypeConverters/serializations,因为它们破坏了数据库的正常形式合规性。

对于这种特殊情况,可能值得使用@Relation批注定义关系,它允许将嵌套实体查询到单个对象中,而不会增加声明 a和手动编写所有 SQL 查询的复杂性:@ForeignKey

@Entity
public class MainActivityData {
    @PrimaryKey
    private String userId;
    private String itemOneId;
    private String itemTwoId;
}

@Entity
public class MyListItem {
    @PrimaryKey
    public int id;
    public String ownerUserId;
    public String text;
}

/* This is the class we use to define our relationship,
   which will also be used to return our query results.
   Note that it is not defined as an @Entity */
public class DataWithItems {
    @Embedded public MainActivityData data;
    @Relation(
        parentColumn = "userId"
        entityColumn = "ownerUserId"
    )
    public List<MyListItem> myListItems;
}

/* This is the DAO interface where we define the queries.
   Even though it looks like a single SELECT, Room performs
   two, therefore the @Transaction annotation is required */
@Dao
public interface ListItemsDao {
    @Transaction
    @Query("SELECT * FROM MainActivityData")
    public List<DataWithItems> getAllData();
}
Run Code Online (Sandbox Code Playgroud)

除了这个 1-N 示例之外,还可以定义 1-1 和 NM 关系。

  • 这里唯一理智的答案!不要违反第一范式! (3认同)

Der*_*eru 7

这就是我处理List转换的方式

public class GenreConverter {
@TypeConverter
public List<Integer> gettingListFromString(String genreIds) {
    List<Integer> list = new ArrayList<>();

    String[] array = genreIds.split(",");

    for (String s : array) {
       if (!s.isEmpty()) {
           list.add(Integer.parseInt(s));
       }
    }
    return list;
}

@TypeConverter
public String writingStringFromList(List<Integer> list) {
    String genreIds = "";
    for (int i : list) {
        genreIds += "," + i;
    }
    return genreIds;
}}
Run Code Online (Sandbox Code Playgroud)

然后在数据库上我做如下所示

@Database(entities = {MovieEntry.class}, version = 1)
@TypeConverters(GenreConverter.class)
Run Code Online (Sandbox Code Playgroud)

  • 该解决方案错过了不愉快的流程(例如,空字符串和空字符串,空列表)。 (2认同)

liv*_*ove 6

有如上所述的相同错误消息.我想补充一点:如果在@Query中收到此错误消息,则应在@Query注释上方添加@TypeConverters.

例:

@TypeConverters(DateConverter.class)
@Query("update myTable set myDate=:myDate  where id = :myId")
void updateStats(int myId, Date myDate);
Run Code Online (Sandbox Code Playgroud)

....

public class DateConverter {

    @TypeConverter
    public static Date toDate(Long timestamp) {
        return timestamp == null ? null : new Date(timestamp);
    }

    @TypeConverter
    public static Long toTimestamp(Date date) {
        return date == null ? null : date.getTime();
    }
}
Run Code Online (Sandbox Code Playgroud)