Android room persistent library - Comment insérer une classe qui a un champ D'objet List
Dans Android chambre persistante de la bibliothèque comment insérer ensemble du Modèle objet dans la table qui est en soi une autre liste.
Laissez-moi vous montrer ce que je veux dire :
@Entity(tableName = TABLE_NAME)
public class CountryModel {
public static final String TABLE_NAME = "Countries";
@PrimaryKey
private int idCountry;
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;
}
/**
here i am providing a list of coutry information how to insert
this into db along with CountryModel at same time
**/
public List<CountryLang> getCountryLang() {
return countryLang;
}
public void setCountryLang(List<CountryLang> countryLang) {
this.countryLang = countryLang;
}
}
mon DAO ressemble à ceci:
@Dao
public interface CountriesDao{
@Query("SELECT * FROM " + CountryModel.TABLE_NAME +" WHERE isoCode =:iso_code LIMIT 1")
LiveData<List<CountryModel>> getCountry(String iso_code);
@Query("SELECT * FROM " + CountryModel.TABLE_NAME )
LiveData<List<CountryModel>> getAllCountriesInfo();
@Insert(onConflict = REPLACE)
Long[] addCountries(List<CountryModel> countryModel);
@Delete
void deleteCountry(CountryModel... countryModel);
@Update(onConflict = REPLACE)
void updateEvent(CountryModel... countryModel);
}
quand j'appelle database.CountriesDao().addCountries(countryModel);
j'obtiens la pièce suivante db compiler error:
erreur: (58, 31) erreur: Impossible de trouver comment sauvegarder ce champ dans la base de données. Vous pouvez considérer l'ajout d'un convertisseur de type.
devrait-il y avoir une autre table appelée Country? et si c'est le cas, comment dire à la salle de les connecter sur insert statement ?
L'objet CountryLang lui-même ressemble à ceci:
public class CountryLang {
private int idCountry;
private int idLang;
private String name;
public int getIdCountry() {
return idCountry;
}
public void setIdCountry(int idCountry) {
this.idCountry = idCountry;
}
public int getIdLang() {
return idLang;
}
public void setIdLang(int idLang) {
this.idLang = idLang;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
la réponse ressemble à ceci:
"country_lang": [
{
"id_country": 2,
"id_lang": 1,
"name": "Austria"
}
]
pour chaque pays donc il ne va pas y avoir plus d'un article ici. Im confortable de le desgning pour un seul article dans le country_lang liste. Donc je peux juste faire une table pour country_lang et ensuite un peu comment le relier à CountryModel. mais comment ? puis-je utiliser de clé étrangère ? j'espérais ne pas avoir à utiliser un fichier plat. donc tu dis que je dois le stocker comme json ? Est-il recommandé de ne pas utiliser la salle de temporaire ? ce qu'il faut utiliser à la place ?
5 réponses
comme dit Omkar, vous ne pouvez pas. Ici, je décris pourquoi vous devez toujours utiliser @Ignore
annotation selon la documentation: https://developer.android.com/training/data-storage/room/referencing-data.html#understand-no-object-references
vous traiterez l'objet Country dans une table pour récupérer les données de sa compétence seulement; les objets Languages iront à une autre table mais vous pouvez garder la même Dao:
- les objets pays et langues sont indépendants, il suffit de définir la clé primaire avec plus de champs dans l'entité de langue (countryId, languageId). Vous pouvez les enregistrer en série dans la classe de dépôt lorsque le thread actif est le Worker thread: deux requêtes d'inserts au Dao.
- pour charger L'objet pays vous avez le paysid.
- pour charger les objets Languages liés, Vous avez déjà le nom du pays, mais vous devrez attendre ce pays est chargé en premier, avant de charger les langues, de sorte que vous pouvez les mettre dans l'objet parent et le retour de l'objet parent.
- vous pouvez probablement le faire en série dans la classe de dépôt lorsque vous chargez le pays, donc vous chargerez synchroniquement le pays et ensuite les langues, comme vous le feriez du côté du serveur! (sans les bibliothèques ORM).
vous pouvez facilement insérer la classe avec le champ d'objet de liste en utilisant TypeConverter et GSON ,
public class DataConverter {
@TypeConverter
public String fromCountryLangList(List<CountryLang> countryLang) {
if (countryLang == null) {
return (null);
}
Gson gson = new Gson();
Type type = new TypeToken<List<CountryLang>>() {}.getType();
String json = gson.toJson(countryLang, type);
return json;
}
@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 ajouter @TypeConverters
Annotation avant le champ d'objet de votre liste,
@Entity(tableName = TABLE_NAME)
public class CountryModel {
//....
@TypeConverters(DataConverter.class)
public List<CountryLang> getCountryLang() {
return countryLang;
}
//....
}
pour plus d'informations sur les convertisseurs de caractères dans la salle consultez notre blog ici .
vous ne pouvez pas.
la seule façon d'y parvenir est d'utiliser la contrainte @ForeignKey . Si vous voulez garder la liste des objets dans votre POJO parent, vous devez utiliser @Ignore ou fournir un @TypeConverter
pour plus d'informations, suivez ce billet de blog: -
https://www.bignerdranch.com/blog/room-data-storage-for-everyone/
et Code d'échantillon: -
https://github.com/googlesamples/android-architecture-components
voici le convertisseur D'Aman Gupta à Kotlin pour les paresseux Googlers qui aiment copier-coller:
class DataConverter {
@TypeConverter
fun fromCountryLangList(value: List<CountryLang>): String {
val gson = Gson()
val type = object : TypeToken<List<CountryLang>>() {}.type
return gson.toJson(value, type)
}
@TypeConverter
fun toCountryLangList(value: String): List<CountryLang> {
val gson = Gson()
val type = object : TypeToken<List<CountryLang>>() {}.type
return gson.fromJson(value, type)
}
}
Ajouter @Embedded pour l'objet personnalisé champ (voir la suite par exemple)
//this class refers to pojo which need to be stored
@Entity(tableName = "event_listing")
public class EventListingEntity implements Parcelable {
@Embedded // <<<< This is very Important in case of custom obj
@TypeConverters(Converters.class)
@SerializedName("mapped")
public ArrayList<MappedItem> mapped;
//provide getter and setters
//there should not the duplicate field names
}
//add converter so that we can store the custom object in ROOM database
public class Converters {
//room will automatically convert custom obj into string and store in DB
@TypeConverter
public static String
convertMapArr(ArrayList<EventListingEntity.MappedItem> list) {
Gson gson = new Gson();
String json = gson.toJson(list);
return json;
}
//At the time of fetching records room will automatically convert string to
// respective obj
@TypeConverter
public static ArrayList<EventsListingResponse.MappedItem>
toMappedItem(String value) {
Type listType = new
TypeToken<ArrayList<EventsListingResponse.MappedItem>>() {
}.getType();
return new Gson().fromJson(value, listType);
}
}
//Final db class
@Database(entities = {EventsListingResponse.class}, version = 2)
@TypeConverters({Converters.class})
public abstract class AppDatabase extends RoomDatabase {
....
}