Room - save custom object list - android

I'm trying to save List<Object> into Room database.
I get following error:
error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
private java.util.List<xxx.models.OBJECTX> carList;
Room implementation:
#Entity(tableName = "nameOfTable")
class CachedObjectX(
#PrimaryKey
#ColumnInfo(name = "id") val id: Long,
#ColumnInfo(name = "list")
var carList: List<ObjectX>
)
#Dao
interface CachedObjectXDao {
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(list: ArrayList<CachedObjectX>)
#Delete
fun delete(list: ArrayList<CachedObjectX>)
#Query("SELECT * FROM ...")
fun getAll(): ArrayList<CachedObjectX>
}
class CachedObjectXConverter {
companion object {
var gson = Gson()
#TypeConverter
#JvmStatic
fun toInsuredVehicle(json: String): List<ObjectX> {
val type = object : TypeToken<List<ObjectX>>() {}.type
return gson.fromJson(json, type)
}
#TypeConverter
#JvmStatic
fun toJson(torrent: List<ObjectX>): String {
val type = object: TypeToken<List<ObjectX>>() {}.type
return gson.toJson(torrent, type)
}
}
}
#Database(entities = [CachedObjectX::class], version = 1, exportSchema = false)
#TypeConverters(CachedObjectXConverter::class)
abstract class CachedObjectXDb : RoomDatabase() {
companion object {
private const val DB_NAME = "CachedObjectX.db"
val instance: CachedObjectXDb by lazy {
Room.databaseBuilder(
getContext(),
CCchedObjectXDb::class.java,
DB_NAME
).build()
}
}
abstract fun getDao(): CachedObjectXDao
}
Interesting, that I've added TypeConverter, but it still throws error. What is wrong with my implementation? Just started with Room, so there is high chance that something is wrong. Thanks in advance.

You have to make the pojo of ObjectX be an entity too

Related

Error of type convertors in room database

I am trying to make a type convertor for a model class in my app. The model class is given below.
Order
#Entity(tableName = "Orders")
data class Order(
#PrimaryKey
var customerId:String,
var companyId:String,
var orderBookerId:String,
#ColumnInfo(name = "items") var list:List<SelectedProductsModel>
)
SelectedProductsModel
data class SelectedProductsModel(
var quantity: Int,
var skuId: String,
var companyId: String,
var productName: String?,
var vendor_brand_name: String,
var purchasePrice: Int,
var image: String,
var position: Int
):Serializable
now as you can see that in the Order class there is a var list:List<SelectedProductsModel>. I want to write a type converter for this list but i keep getting an error
error: cannot find symbol
#androidx.room.TypeConverters(value = {SelectedProductModelConvertor.class})
following is my Room database class
#Database(entities = [VisitedPjpModel::class,Order::class], version = 1)
#TypeConverters(SelectedProductModelConvertor::class)
abstract class RoomDatabaseClass : RoomDatabase()
{
public abstract fun visitedDao(): VisitedPjpDao
public abstract fun orderDao():OrderDao
companion object
{
private var instance: RoomDatabaseClass? = null
fun getInstance(context: Context): RoomDatabaseClass?
{
if (instance == null)
{
synchronized(RoomDatabaseClass::class)
{
instance = Room.databaseBuilder(context, RoomDatabaseClass::class.java, "tarseel_database").allowMainThreadQueries().build()
}
}
return instance
}
}
}
i have tried different implementations of type convertors but iam getting the same error which is mentioned above. following are the implementations of type converotrs that i have tried
class SelectedProductModelConvertor
{
#TypeConverter
fun fromList(value : List<SelectedProductsModel>) = Json.encodeToString(value)
#TypeConverter
fun toList(value: String) = Json.decodeFromString<List<SelectedProductsModel>>(value)
}
class SelectedProductModelConvertor
{
#TypeConverter
fun listToJson(value: List<SelectedProductsModel>) = Gson().toJson(value)
#TypeConverter
fun jsonToList(value: String) = Gson().fromJson(value, Array<SelectedProductsModel>::class.java).toList()
}
class SelectedProductModelConvertor
{
#TypeConverter
fun fromListLangList(value: List<SelectedProductsModel>): String
{
val gson = Gson()
val type = object : TypeToken<List<SelectedProductsModel>>()
{}.type
return gson.toJson(value, type)
}
#TypeConverter
fun toSelectedProductsModelList(value: String): List<SelectedProductsModel>
{
val gson = Gson()
val type = object : TypeToken<List<SelectedProductsModel>>()
{}.type
return gson.fromJson(value, type)
}
}
I have tried all these type convertors but iam getting error. please help me
You cannot have a List/Array for a column.
What you can do, is have a class that holds the List/Array and have a Type Converter for that.
So you could have:-
data class SelectedProductsModelList(
val selectedProductsModelList: List<SelectedProductsModel>
)
Then have :-
#Entity(tableName = "Orders")
data class Order(
#PrimaryKey
var customerId:String,
var companyId:String,
var orderBookerId:String,
#ColumnInfo(name = "items") var list:SelectedProductsModelList //<<<<<<<<<<
)
and TypeConverters that convert from/to a SelectProductsModelList object e.g.
#TypeConverter
fun fromSelectedProductsModelList(selectedProductsModelList: SelectedProductsModelList): String {
return Gson().toJson(selectedProductsModelList)
}
#TypeConverter
fun toSelectedProductsModelList(json: String): SelectedProductsModelList {
return Gson().fromJson(json,SelectedProductsModelList::class.java)
}

Cannot figure out how to save this field into database. I have written data class,dao and typeconverters, but still unable to detect error

MyData.kt
#Entity(tableName = "my_table")
data class MyData(
#PrimaryKey(autoGenerate = true)
var id: Long = 0L,
#ColumnInfo(name = "ListData")
#TypeConverters(DataTypeConverter::class)
var mList: List<User> = emptyList(),
#Embedded
var user: User
)
MyDataDao.kt
#Dao
interface MyDataDao {
#Insert
suspend fun insert(data: MyData)
#Update
suspend fun update(data: MyData)
#Query("SELECT * FROM my_table")
fun getAll(): LiveData<List<MyData>>
}
DataTypeConverter.kt
import androidx.room.TypeConverter
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
class DataTypeConverter {
companion object {
inline fun <reified T> Gson.fromJson(json: String) =
fromJson<T>(json, object : TypeToken<T>() {}.type)
#TypeConverter
fun stringToList(data: String?): List<User> {
data?.let {
return Gson().fromJson(data)
}
return emptyList()
}
#TypeConverter
fun listToString(users: List<User>): String {
return Gson().toJson(users)
}
}
}
User.kt
data class User(
#ColumnInfo(name = "first_name")
val firstName: String,
#ColumnInfo(name = "last_name")
val lastName: String
)
on build getting this error
error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
Even after using typeconverters the problem is persistent
I think your DataTypeConverter is wrong you can try change like this :
class DataTypeConverter{
var gson = Gson()
#TypeConverter
fun stringToUserList(data: String?): List<User?>? {
if (data == null) {
return Collections.emptyList()
}
val listType: Type =
object : TypeToken<List<User?>?>() {}.type
return gson.fromJson<List<User?>>(data, listType)
}
#TypeConverter
fun userDetailListToString(someObjects: List<User?>?): String? {
return gson.toJson(someObjects)
}
}
Don't forget to add #TypeConverters(DataTypeConverter::class) to #Database

Android room/TypeConverter issue while retriving list of objects

I am implementing a local cache using Room. I have created typeconverter to convert list of objects to json and back. But I am receiving mapping issue while retrieving data from json with error:
The columns returned by the query does not have the fields [title,media] in
com.example.theApp.data.FlickrImage even though they are annotated as non-null or
primitive. Columns returned by the query: [items]
Another one like this:
error: Cannot figure out how to read this field from a cursor.
private final com.example.theApp.data.Media media = null;
I tried other answers here but its not associated directly with this issue.
Here is my typeconverter:
class FlickrImageConverters {
#TypeConverter
fun fromImageListToJson(stat: List<FlickrImage>): String {
return Gson().toJson(stat)
}
/**
* Convert a json to a list of Images
*/
#TypeConverter
fun fromJsonToImagesList(jsonImages: String): List<FlickrImage> {
val type = object : TypeToken<List<FlickrImage>>() {}.type
return Gson().fromJson<List<FlickrImage>>(jsonImages, type)
}
}
Here is my entity class:
#Entity
data class DatabaseImagesEntity(
#PrimaryKey
#TypeConverters(FlickrImageConverters::class)
#SerializedName("item")
val items: List<FlickrImage>)
Dao class
#Dao
interface ImagesDao {
#Query("select * from DatabaseImagesEntity")
fun getImages(): List<FlickrImage>
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(images: List<FlickrImage>)
}
FlickrImage class
data class FlickrImage(val title: String, val media: Media)
Media class
data class Media(val m: String)
LatestImage class
data class LatestImages(val items: List<FlickrImage>)
Please let me know if you faced this issue and if you know the solution for this.
Room database implementation
#Database(entities = [DatabaseImagesEntity::class], version = 1,
exportSchema = false)
#TypeConverters(FlickrImageConverters::class)
abstract class FlickrDatabase: RoomDatabase() {
abstract val imagesDao: ImagesDao
}
private lateinit var INSTANCE: FlickrDatabase
fun getDatabase(context: Context): FlickrDatabase{
synchronized(FlickrDatabase::class.java){
if(!::INSTANCE.isInitialized){
INSTANCE = Room.databaseBuilder(context.applicationContext,
FlickrDatabase::class.java,
"flickerImages").build()
}
}
return INSTANCE
}
The issue was I was saving data in the wrong entity, wrong TypeConverters and as a result, I was using the wrong Entity class at the time of database creation.
Here are the necessary changes I had to make to store the list of objects:
Flickr data class
#Entity(tableName = "FlickerImage")
data class FlickrImage(
#PrimaryKey(autoGenerate = true)
val id: Int,
val title: String,
#TypeConverters(MediaConverter::class)
val media: Media)
TypeConvertors for Media class
class MediaConverter {
#TypeConverter
fun fromMediaToJson(stat: Media): String {
return Gson().toJson(stat)
}
/**
* Convert a json to a list of Images
*/
#TypeConverter
fun fromJsonToMedia(jsonImages: String): Media {
val type = object : TypeToken<Media>() {}.type
return Gson().fromJson<Media>(jsonImages, type)
}
}
DAO class
#Dao
interface ImagesDao {
#Query("select * from FlickerImage")
fun getImages(): LiveData<List<FlickrImage>>
Database class
#Database(entities = [FlickrImage::class], version = 1, exportSchema = false)
#TypeConverters(MediaConverter::class)
abstract class FlickrDatabase: RoomDatabase() {
abstract val imagesDao: ImagesDao
}
private lateinit var INSTANCE: FlickrDatabase
fun getDatabase(context: Context): FlickrDatabase{
synchronized(FlickrDatabase::class.java){
if(!::INSTANCE.isInitialized){
INSTANCE = Room.databaseBuilder(context,
FlickrDatabase::class.java,
"flickerImages").build()
}
}
return INSTANCE
}
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(images: List<FlickrImage>)
}
You need to add the appropriate annotations to your data class - e.g. for Gson you need to add the annotations #SerializedName("field_name") Otherwise, there's no way for the converters to know how to translate the json.
To clarify, the current annotations you have are only for Room. Just check with whatever json library you are using for the necessary logic.
#Entity(tableName = "images")
data class DatabaseImagesEntity(
#PrimaryKey(autoGenerate = true)
var id: Int? = 0,
#TypeConverters(FlickrImageConverters::class)
#SerializedName("item")
val items: MutableList<FlickrImage>? = null
)
or
#Entity(tableName = "images")
class DatabaseImagesEntity {
#PrimaryKey(autoGenerate = true)
var id: Int? = 0
#TypeConverters(FlickrImageConverters::class)
#SerializedName("item")
val items: MutableList<FlickrImage>? = null
}
then update your DAO query to #Query("select * from images")
I named it images as an example - you can choose whatever you want.
class ListConverter {
//from List to String
#TypeConverter
fun fromList(list : List<Object>): String {
return Gson().toJson(list)
}
// from String to List
#TypeConverter
fun toList(data : String) : List<Object> {
if (data == null){
return Collections.emptyList()
}
val typeToken = object : TypeToken<List<Object>>() {}.type
return Gson().fromJson(data,typeToken)
}
}

Android room save custom type

I try save custom type in room database. I always getting an error
error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
I created converter for OutboxItemCache
My entity
#Entity(tableName = "request")
class RequestCache(
#ColumnInfo(name = "requestId")
#PrimaryKey var id: String = "",
#TypeConverters(RequestConverter::class)
var outboxItemCache: OutboxItemCache)
My RequestConverter
class RequestConverter {
companion object {
private val gson = Gson()
#TypeConverter
fun stringToOutboxItem(string: String): OutboxItemCache? {
if (TextUtils.isEmpty(string))
return null
return gson.fromJson(string, OutboxItemCache::class.java)
}
#TypeConverter
private fun outboxItemToString(outboxItem: OutboxItemCache): String {
return gson.toJson(outboxItem)
}
}
}
This my class OutboxItemCache
class OutboxItemCache(
var id: String = "",
val numder: String,
date: String,
val headerDate: String,
name: String,
val certCount: String,
val status: String,
val statusColor: Int,
var statusInfo: String? = null,
val vetCertIds: List<String>
)
The error never disappeared
As per google's documentation:
#Database(entities = {User.class}, version = 1)
#TypeConverters({RequestConverter.class})
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}
You need to register your TypeConverters to your Database class.
EDIT:
In kotlin:
#Database(entities = arrayOf(User::class), version = 1)
#TypeConverters(RequestConverter::class)
abstract class AppDatabse : RoomDatabase() {
abstract fun userDAO(): UserDAO
}
The only line of code here that matters to you is
#TypeConverters(RequestConverter::class)
as you should already have the others.
EDIT 2:
Try writing your converter class as follows:
class RequestConverter {
#TypeConverter
fun stringToOutboxItem(string: String): OutboxItemCache? {
if (TextUtils.isEmpty(string))
return null
return Gson().fromJson(string, OutboxItemCache::class.java)
}
#TypeConverter
private fun outboxItemToString(outboxItem: OutboxItemCache): String {
return Gson().toJson(outboxItem)
}

Android Room Cannot figure out how to save this field into database

I'm try to using save values to database via room persistance library. My SettingsValueModelConverter is wrong somethings are missing. How I can save SettingsKeyContract objects best way?
Logcat:
SettingsModel
Error:(14, 1) error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
Codes:
object SETTING_CONS{
const val TABLE = "Content_Setting"
const val ID = "uid"
const val KEY = "key"
const val VALUE = "value"
}
class SettingsValueModel(var value: SettingsKeyContract)
class SettingsValueModelConverter {
#TypeConverter
fun fromString(value: String): SettingsKeyContract = Gson().fromJson(value, object : TypeToken<SettingsKeyContract>() {}.type)
#TypeConverter
fun fromModel(value: SettingsKeyContract): String = Gson().toJson(value)
}
#Entity(tableName = SETTING_CONS.TABLE)
class SettingsModel(#ColumnInfo(name = SETTING_CONS.KEY) #SETTINGS var key: String,
#ColumnInfo(name = SETTING_CONS.VALUE) var value: SettingsValueModel) {
#ColumnInfo(name = SETTING_CONS.ID)
#PrimaryKey(autoGenerate = true)
var uid: Int = 0
}
#Dao
interface SettingsDao {
#Query("SELECT * FROM ${SETTING_CONS.TABLE} WHERE ${SETTING_CONS.ID} = :key")
fun get(#SETTINGS key: String): LiveData<SettingsModel>
#get:Query("SELECT * FROM ${SETTING_CONS.TABLE}")
val all: LiveData<MutableList<SettingsModel>>
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(model: SettingsModel): Long
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(vararg models: SettingsModel): LongArray
#Query("DELETE FROM ${SETTING_CONS.TABLE} WHERE ${SETTING_CONS.KEY} = :key")
fun delete(#SETTINGS key: String)
#Query("DELETE FROM ${SETTING_CONS.TABLE}")
fun clear()
}
interface SettingsKeyContract { val key: String }
interface TypeSettingsKeyContract<out T : Any> : SettingsKeyContract { val default: T }
sealed class SETTING(override val key: String) : SettingsKeyContract {
object FIRST_LAUNCH_DATE : SETTING("first_launch_date"), TypeSettingsKeyContract<Long> { override val default = 0L }
}
Where do you define your database?
You should have the option there to specify which converter to use, like such :
#Database(entities = arrayOf(SettingsModel::class) , version = 1, exportSchema = false)
#TypeConverters(SettingsValueModelConverter::class)
abstract class AppDatabase: RoomDatabase() {
abstract fun SettingsDao(): SettingsDao
}

Categories

Resources