web-dev-qa-db-fra.com

Android Room Database: Comment gérer Arraylist dans une entité?

Je viens d'implémenter Room pour la sauvegarde des données hors ligne. Mais dans une classe d'entité, j'obtiens l'erreur suivante:

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

Et la classe est comme suit:

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

Donc, fondamentalement, je veux sauvegarder ArrayList dans la base de données mais je n’ai rien trouvé de pertinent. Pouvez-vous me guider sur la façon de sauvegarder un tableau en utilisant Room?

REMARQUE: la classe MyListItems Pojo contient 2 chaînes (à ce jour).

Merci d'avance.

45
Tushar Gogna

Option n ° 1: Avoir MyListItems un @Entity, comme MainActivityData. MyListItems configurerait un @ForeignKey de nouveau à MainActivityData. Dans ce cas, cependant, MainActivityData ne peut pas avoir private ArrayList<MyListItems> myListItems, comme dans Room, les entités ne font pas référence à d'autres entités. Un modèle de vue ou une construction POJO similaire pourrait avoir une MainActivityData et son ArrayList<MyListItems> associé, cependant.

Option n ° 2: Configurez une paire de méthodes @TypeConverter pour convertir ArrayList<MyListItems> en un type de base (par exemple, un String, par exemple en utilisant JSON comme format de stockage). Maintenant, MainActivityData peut avoir son ArrayList<MyListItems> directement. Cependant, il n'y aura pas de table séparée pour MyListItems et vous ne pourrez donc pas interroger très bien sur MyListItems.

53
CommonsWare

Type Converter sont spécialement conçus pour cela. Dans votre cas, vous pouvez utiliser l'extrait de code donné ci-dessous pour stocker des données dans une base de données.

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

Et mentionnez cette classe dans votre Room DB comme ceci

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

Plus d'infos ici

64
Amit Bhandari

Kotlin version pour le convertisseur de type:

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

J'ai utilisé l'objet JobWorkHistory pour mon objectif, utilisez l'objet de votre choix

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

Voici comment je gère la conversion de liste

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

Et puis sur la base de données je fais comme indiqué ci-dessous

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

Et ci-dessous est une implémentation kotlin de la même chose;

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
}}
7
Derrick Njeru

A eu le même message d'erreur comme décrit ci-dessus. J'aimerais ajouter ceci: si vous recevez ce message d'erreur dans un @Query, vous devez ajouter @TypeConverters au-dessus de l'annotation @Query.

Exemple:

@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
live-love

Cette réponse utilise Kotin pour scinder par une virgule et construire la chaîne délimitée par une virgule. La virgule doit être placée à la fin de tous les éléments sauf le dernier, elle gérera également les listes d'éléments uniques.

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
        }
    }
1
Daniel Wilson

Les conversions JSON ne s'échelonnent pas bien en termes d'allocation de mémoire. Je préférerais obtenir quelque chose de similaire aux réponses ci-dessus avec une certaine nullabilité.

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(",")
    }
}

Pour les types de données simples, on peut utiliser ce qui précède, sinon pour les types de données complexes, la pièce fournit Embedded

0
Dokuzov

Ajout de @TypeConverters avec la classe de convertisseur en tant que params

à la base de données et à la classe Dao, mes requêtes ont fonctionné

0
abitcode

Meilleure version du convertisseur 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 = ",")
    }
}
0
Nitin Misra