База данных Android для Android: как обрабатывать Arraylist в сущности?

Я только что внедрил 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.

И класс следующий:

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

Итак, в основном я хочу сохранить ArrayList в базе данных, но я не смог найти что-либо, относящееся к нему. Можете ли вы посоветовать мне, как сохранить массив с помощью комнаты?

ПРИМЕЧАНИЕ. Класс MyListItems Pojo содержит 2 строки (на данный момент)

Спасибо заранее.

Ответ 1

Вариант №1: MyListItems должен быть @Entity, как MainActivityData. MyListItems установит @ForeignKey обратно на MainActivityData. В этом случае, однако, MainActivityData не может иметь private ArrayList<MyListItems> myListItems, как в комнате, объекты не относятся к другим объектам. Модель просмотра или аналогичная конструкция POJO может иметь MainActivityData и связанный с ней ArrayList<MyListItems>.

Вариант №2: Настройте пару методов @TypeConverter для преобразования ArrayList<MyListItems> в и из некоторого базового типа (например, a String, например, используя JSON в качестве формата хранения). Теперь MainActivityData может иметь свой ArrayList<MyListItems> напрямую. Однако для MyListItems не будет отдельной таблицы, поэтому вы не можете запросить на MyListItems очень хорошо.

Ответ 2

Тип Converter специально для этого. В вашем случае вы можете использовать приведенный ниже фрагмент кода для хранения данных в БД.

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

И упоминаем этот класс в вашей комнате DB, как это

@Database (entities = {MainActivityData.class},version = 1)
@TypeConverters({Converters.class})

Подробнее здесь

Ответ 3

Версия 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
    }
}

Я использовал объект JobWorkHistory для своих целей, используйте свой собственный объект

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

Ответ 4

Вот как я справляюсь с преобразованием списка

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

А затем в базе данных я делаю, как показано ниже

@Database(entities = {MovieEntry.class}, version = 1)
@TypeConverters(GenreConverter.class)

А ниже приведена одна и та же реализация kotlin;

class GenreConverter {
@TypeConverter
fun gettingListFromString(genreIds: String): List<Int> {
    val list = mutableListOf<Int>()

    val array = genreIds.split(",".toRegex()).dropLastWhile {
        it.isEmpty()
    }.toTypedArray()

    for (s in array) {
        if (s.isNotEmpty()) {
            list.add(s.toInt())
        }
    }
    return list
}

@TypeConverter
fun writingStringFromList(list: List<Int>): String {
    var genreIds=""
    for (i in list) genreIds += ",$i"
    return genreIds
}}

Ответ 5

Имело такое же сообщение об ошибке, как описано выше. Я хотел бы добавить: если вы получите это сообщение об ошибке в @Query, вы должны добавить @TypeConverters над аннотацией @Query.

Пример:

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

....

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

Ответ 6

Лучшая версия конвертера 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 = ",")
    }
}

Ответ 7

Этот ответ использует Kotin для разделения через запятую и построения строки, разделенной запятой. Запятая должна идти в конце всех элементов, кроме последнего, поэтому она будет обрабатывать и списки отдельных элементов.

object StringListConverter {
        @TypeConverter
        @JvmStatic
        fun toList(strings: String): List<String> {
            val list = mutableListOf<String>()
            val array = strings.split(",")
            for (s in array) {
                list.add(s)
            }
            return list
        }

        @TypeConverter
        @JvmStatic
        fun toString(strings: List<String>): String {
            var result = ""
            strings.forEachIndexed { index, element ->
                result += element
                if(index != (strings.size-1)){
                    result += ","
                }
            }
            return result
        }
    }

Ответ 8

Добавление @TypeConverters с классом конвертера в качестве параметров

к базе данных и к классу Дао, заставил мои запросы работать

Ответ 9

Преобразования Json плохо масштабируются с точки зрения распределения памяти. Я бы предпочел что-то похожее на ответы выше с некоторой обнуляемостью.

class Converters {
    @TypeConverter
    fun stringAsStringList(strings: String?): List<String> {
        val list = mutableListOf<String>()
        strings
            ?.split(",")
            ?.forEach {
                list.add(it)
            }

        return list
    }

    @TypeConverter
    fun stringListAsString(strings: List<String>?): String {
        var result = ""
        strings?.forEach { element ->
            result += "$element,"
        }
        return result.removeSuffix(",")
    }
}

Для простых типов данных можно использовать вышеуказанное, в противном случае для сложных типов данных Room предоставляет Embedded

Ответ 10

Используйте официальное решение из комнаты, @Встроенная аннотация:

@Embedded(prefix = "mylist_array") private ArrayList<MyListItems> myListItems