tutorial room library example ejemplo android android-room

library - sample room android



Biblioteca persistente de la sala Android: cómo insertar una clase que tiene un campo Objeto de lista (5)

En la biblioteca persistente de la sala Android, cómo insertar todo el objeto Modelo en la tabla, que tiene en sí misma otra lista.

Déjame mostrarte lo que quiero decir:

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

mi DAO se ve así:

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

Cuando llamo database.CountriesDao().addCountries(countryModel); Obtengo el siguiente error de compilación de la base de datos de la sala: Error: (58, 31) error: No puedo averiguar cómo guardar este campo en la base de datos. Puedes considerar agregar un convertidor de tipos para ello.

¿Debería haber otra tabla llamada CountryLang? y si es así, ¿cómo decirle a la sala que los conecte en la declaración de inserción?

El objeto CountryLang se parece a esto:

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 respuesta se ve así:

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

Para cada país, por lo que no va a ser más de un elemento aquí. Me siento cómodo al diseñarlo para un solo elemento de la lista country_lang. Así que solo puedo hacer una tabla para country_lang y luego algunas formas de vincularla a CountryModel. pero cómo ? ¿Puedo usar clave externa? Esperaba no tener que usar un archivo plano. ¿Entonces tu diciendo que tengo que guardarlo como json? ¿Se recomienda no usar espacio para temporales? ¿Qué usar en su lugar?


Agregue @Embedded para el campo de objeto personalizado (refiérase a continuación, por ejemplo)

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


Aquí está el convertidor de Aman Gupta en Kotlin para los holgazanes perezosos que disfrutan de pegar copias:

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


Como dijo Omkar, no puedes. Aquí, describo por qué siempre debe usar la anotación @Ignore acuerdo con la documentación: https://developer.android.com/training/data-storage/room/referencing-data.html#understand-no-object-references

Usted tratará el objeto País en una tabla para recuperar los datos de su competencia solamente; Los objetos de Idiomas irán a otra tabla, pero puedes mantener el mismo Dao:

  • Los objetos de Países e Idiomas son independientes, simplemente defina la Clave principal con más campos en la entidad de Idioma (countryId, languageId). Puede guardarlos en serie en la clase Repositorio cuando el subproceso activo es el subproceso de trabajo: dos solicitudes de inserciones al Dao.
  • Para cargar el objeto Países tienes el countryId.
  • Para cargar los objetos de Idiomas relacionados, ya tiene el ID de país, pero deberá esperar a que ese país se cargue primero, antes de cargar los idiomas, para poder establecerlos en el objeto principal y devolver solo el objeto principal.
  • Probablemente pueda hacer esto en serie en la clase Repositorio cuando cargue el país, por lo que cargará el país y luego los idiomas de forma síncrona, ¡como lo haría en el lado del Servidor! (sin bibliotecas ORM).


Puede insertar fácilmente la clase con el campo de objeto de lista utilizando TypeConverter y 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; } }

Y añada @TypeConverters Annotation antes de su campo de objeto de lista,

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

Para obtener más información acerca de TypeConverters in Room, consulte nuestro blog here .