A persistent library in an Android room - how to insert a class that has a List of Objects field

In the Android room, a permanent library is how to insert the entire Model object into a table that has a different list.

Let me show you what I mean:

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

my DAO looks like this:

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

When I call database.CountriesDao().addCountries(countryModel); I get the following database compilation error: Error: (58, 31) error: I canโ€™t figure out how to save this field in the database. You might consider adding a type converter for it.

should there be another table named CountryLang? and if so, how do I specify the number to link them in the insert statement?

The CountryLang object itself looks like this:

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

The answer looks like this:

 "country_lang": [ { "id_country": 2, "id_lang": 1, "name": "Austria" } ] 

For each country, therefore, there will not be more than one point. Itโ€™s more convenient for me to call it only one element in the country_lang list. So I can just make a table for country_lang and then somehow link it to CountryModel. but how? can i use a foreign key? I was hoping that I did not need to use a flat file. so you say i have to store it as json? It is recommended not to use the room for temporary? what to use instead?

+25
android android room
source share
5 answers

As Omkar said, you cannot. Here I will describe why you should always use the @Ignore annotation according to the documentation: https://developer.android.com/training/data-storage/room/referencing-data.html#understand-no-object-references

You will process the Country object in the table to receive data only on its competence; Languages โ€‹โ€‹objects will fall into another table, but you can leave the same Tao:

  • The Country and Language objects are independent, just define a primaryKey with many fields in the Language object (countryId, languageId). You can save them sequentially in the Repository class when the active thread is a workflow: two insert requests in Dao.
  • To load the Country object, you have a country identifier.
  • To download the associated Languages โ€‹โ€‹objects, you already have a countryId, but you will need to wait until this country is loaded before loading the languages โ€‹โ€‹so that you can install them in the parent and return only the parent.
  • You can probably do this sequentially in the Repository class when loading the country, so you will load the country synchronously and then languages, as you would do on the server side! (without ORM libraries).
+11
source share

You can easily insert a class with an object list field using TypeConverter and 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; } } 

And add the @TypeConverters annotation @TypeConverters front of the object list field,

 @Entity(tableName = TABLE_NAME) public class CountryModel { //.... @TypeConverters(DataConverter.class) public List<CountryLang> getCountryLang() { return countryLang; } //.... } 

For more information on room type converters, visit our blog here and white papers .

+60
source share

Here is the Aman Gupta to Kotlin converter for the lazy googler who love copying:

 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) } } 
+7
source share

You can not.

The only way to achieve this is to use the @ForeignKey constraint. If you want to keep a list of objects inside your parent POJO, you must use @Ignore or provide @TypeConverter

For more information, follow this blog post: -

https://www.bignerdranch.com/blog/room-data-storage-for-everyone/

and sample code: -

https://github.com/googlesamples/android-architecture-components

+6
source share

Add @Embedded for the custom object field (see, for example, the following)

 //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 { .... } 
0
source share

All Articles