web-dev-qa-db-fra.com

Bibliothèque de salle persistante Android - Erreur typeConverter: impossible de savoir comment enregistrer le champ dans la base de données "

Je ne parviens pas à créer un convertisseur de type dans la chambre à cause d'une erreur. Je semble suivre tout selon les docs. Je voudrais convertir une liste en une chaîne json. Regardons mon entité:

      @Entity(tableName = TABLE_NAME)
public class CountryModel {

    public static final String TABLE_NAME = "Countries";

    @PrimaryKey
    private int idCountry;
/* I WANT TO CONVERT THIS LIST TO A JSON STRING */
    private List<CountryLang> countryLang = null;

    public int getIdCountry() {
        return idCountry;
    }

    public void setIdCountry(int idCountry) {
        this.idCountry = idCountry;
    }

    public String getIsoCode() {
        return isoCode;
    }

    public void setIsoCode(String isoCode) {
        this.isoCode = isoCode;
    }

    public List<CountryLang> getCountryLang() {
        return countryLang;
    }

    public void setCountryLang(List<CountryLang> countryLang) {
        this.countryLang = countryLang;
    }

}

Le country_lang est ce que je voudrais convertir en chaîne json. J'ai donc créé le convertisseur suivant: Converters.Java:

public class Converters {

@TypeConverter
public static String countryLangToJson(List<CountryLang> list) {

    if(list == null)
        return null;

        CountryLang lang = list.get(0);

    return list.isEmpty() ? null : new Gson().toJson(lang);
}}

alors le problème est n'importe où je mets les @TypeConverters ({Converters.class}) je continue à obtenir une erreur. Mais officiellement, c’est là que j’ai placé l’annotation pour obtenir le typeConverter enregistré:

@Database(entities = {CountryModel.class}, version = 1 ,exportSchema = false)
@TypeConverters({Converters.class})
public abstract class MYDatabase extends RoomDatabase {
    public abstract CountriesDao countriesDao();
}

L'erreur que je reçois est:

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

C’est un problème courant que j’ai vu depuis l’annonce de Room. Room ne prend pas en charge la possibilité de stocker directement des listes, ni la possibilité de convertir vers/à partir de listes. Il prend en charge la conversion et le stockage des POJO.

Dans ce cas, la solution est simple. Au lieu de stocker un List<CountryLang>, vous souhaitez stocker CountryLangs (notez le 's')

J'ai fait un exemple rapide d'une solution ici: 

public class CountryLangs {
    private List<String> countryLangs;

    public CountryLangs(List<String> countryLangs) {
        this.countryLangs = countryLangs;
    }

    public List<String> getCountryLangs() {
        return countryLangs;
    }

    public void setCountryLangs(List<String> countryLangs) {
        this.countryLangs = countryLangs;
    }
}

Ce POJO est une inversion de votre objet précédent. C'est un objet qui stocke une liste de langues. Au lieu d'une liste d'objets qui stockent votre langue. 

public class LanguageConverter {
    @TypeConverter
    public CountryLangs storedStringToLanguages(String value) {
        List<String> langs = Arrays.asList(value.split("\\s*,\\s*"));
        return new CountryLangs(langs);
    }

    @TypeConverter
    public String languagesToStoredString(CountryLangs cl) {
        String value = "";

        for (String lang :cl.getCountryLangs())
            value += lang + ",";

        return value;
    }
}

Ce convertisseur prend une liste de chaînes et les convertit en une chaîne séparée par des virgules à stocker dans une seule colonne. Lorsqu'il extrait la chaîne de la base de données SQLite pour la reconvertir, il divise la liste en virgules et remplit les CountryLangs.

Assurez-vous de mettre à jour votre version de RoomDatabase après avoir apporté ces modifications. Le reste de la configuration est correct. Bonne chasse avec le reste de votre travail de persistance de la chambre.

21
Jack Dalton

Avait la même erreur: "Impossible de comprendre comment enregistrer ce champ dans la base de données" lors de l'ajout d'un champ Date. Il a fallu ajouter une classe de convertisseur et ajouter l'annotation @TypeConverters à field.

Exemple:

WordEntity.Java

import Android.Arch.persistence.room.TypeConverters;

    @Entity
    public class WordEntity {

        @PrimaryKey(autoGenerate = true)
        public int id;
        private String name;
        @TypeConverters(DateConverter.class)
        private Date createDate;

DateConverter.Java:

import Android.Arch.persistence.room.TypeConverter;

import Java.util.Date;

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

@TypeConverter ne reconnaît pas la classe List; vous devez donc utiliser ArrayList à la place, vous n'avez donc pas besoin d'encapsuleur supplémentaire pour la liste que vous souhaitez conserver.

3
Eduards Pozarickis

Vous devez également créer cette TypeConverter qui convertira votre List en String,

@TypeConverter
public List<CountryLang> toCountryLangList(String countryLangString) {
    if (countryLangString == null) {
        return (null);
    }
    Gson gson = new Gson();
    Type type = new TypeToken<List<CountryLang>>() {}.getType();
    List<CountryLang> countryLangList = gson.fromJson(countryLangString, type);
    return countryLangList;
}

Et pour plus d’informations, vous pouvez également consulter mon autre répondre .

1

Exemple Kotlin (pas bon mais simple, TODO: json):

import Android.Arch.persistence.room.*

@Entity(tableName = "doctor")
data class DoctorEntity(

    @PrimaryKey
    @ColumnInfo(name = "id") val id: Long,

    @ColumnInfo(name = "contactName") val contactName: String?,

    @TypeConverters(CategoryConverter::class)
    @ColumnInfo(name = "categories") val categories: Categories?,

    @TypeConverters(CategoryConverter::class)
    @ColumnInfo(name = "languages") val languages: Categories?
) 

data class Categories(
    val categories: ArrayList<Long> = ArrayList()
)

class CategoryConverter {

    @TypeConverter
    fun toCategories(value: String?): Categories {
        if (value == null || value.isEmpty()) {
            return Categories()
        }

        val list: List<String> = value.split(",")
        val longList = ArrayList<Long>()
        for (item in list) {
            if (!item.isEmpty()) {
                longList.add(item.toLong())
            }
        }
        return Categories(longList)
    }

    @TypeConverter
    fun toString(categories: Categories?): String {

        var string = ""

        if (categories == null) {
            return string
        }

        categories.categories.forEach {
            string += "$it,"
        }
        return string
    }
}
0
norbDEV

J'ai utilisé les convertisseurs de type décrits ici (article sur Medium.com) et cela a fonctionné:

@TypeConverter
    public static List<MyObject> storedStringToMyObjects(String data) {
        Gson gson = new Gson();
        if (data == null) {
            return Collections.emptyList();
        }
        Type listType = new TypeToken<List<MyObject>>() {}.getType();
        return gson.fromJson(data, listType);
    }

    @TypeConverter
    public static String myObjectsToStoredString(List<MyObject> myObjects) {
        Gson gson = new Gson();
        return gson.toJson(myObjects);
    }
0
MorZa