room database with list inside an object - android

Till this time I was only doing sql queries which had only simple types or objects where annotation #Embedded was doing a job. Currently I have to extend my sql query to receive "simple data" in the list inside.
data class SimpleDataClass(
#Embedded val myObject: MyObject,
val id: UUID,
val listOfNumbers: List<MyNumbers>)
where
data class MyNumbers( val number: Int)
How to do this? By sql statement? Somehow with code? In DAO I return a:
LiveData<List<SimpleDataClass>>
When I try to receive data as before I get:
Entities and POJOs must have a usable public constructor. You can have an >empty constructor or a constructor whose parameters match the fields (by >name and type). - java.util.List

You provide very few information about your problem, but I think that Room relations is what you need. See this article Database relations with Room, should be helpful.

Related

android Room with kotlin value class?

I'm trying to use a room entity with a value class:
#JvmInline
value class UserToken(val token: String)
and the entity:
#Entity(tableName = TABLE_AUTH_TOKEN)
data class TokenEntity(
#PrimaryKey val id: Int = 0,
val token: UserToken
)
I get the following error:
error: Entities and POJOs must have a usable public constructor. You can have an empty constructor or a constructor whose parameters match the fields (by name and type).
public final class TokenEntity {
^
is it even possible to use room with value class? I couldn't find anything about this. thanks
See the comment from #CommonsWare. Android does not yet support value classes for Room.
The same holds true for the value classes introduced in kotlin 1.5. The type is not supported.
— Support Inline class in Room entity
Here is a possible explanation according to Kotlin Inline Classes in an Android World.
Looking to solve this you could try and add a TypeConverter for your Inline class, but since your Inline class is just the value it wraps when it’s compiled, this doesn’t make much sense and it doesn’t work as you’d expect even if you tried...
I’m just guessing it’s because this is a TypeConverter converting UserId to Int which is basically the same as Int to Int 😭. Someone will probably solve this problem, but if you have to create a TypeConverter for your Inline class then you are still plus one class for the count (multidex). 👎
I think yes if you can provide a type converter for it to change it to some sort of primitive data type (int , string, long ...etc) when it needs to be stored, and to change it back to its class type when it's fetched from database.
You can read about Type Converters from here
Referencing complex data using Room
other than that, your other class should be an entity and bind both your entities together using a Relation.
at least that's what I know about how to use Room.
UserToken always will have only one attribute? In this case, you don't need two classes, just use token: String directly on your entity class;
If you really need keep this class, you have two options:
TypeConverter, where you basically will convert the object into a json, and save as string in the database;
Relation, where you will transform the UserToken in a entity, and on TokenEntity save the tokenId.

Room is there any way to not insert/update value if null

I've recentyly started using Room and I would like to know if when inserting or updating an Entitiy there's any way to check if the value is null, and in that case, do not insert it /update it.
What I want to do is something like
#Entity
data class Person{
#PrimaryKey
val id: Int,
val name:String
val surname:String
}
Would it be possible in a simple way to perform an #Update operation for those fields which are not null? and those which are null keep them as tey are?
For example in an update perhaps I might have informed the id and the name, but in another update I might have informed the id and the surname. So what I want is to merge the information, but if possible without having to make a select query to check the values stored.
I've read the following post, but my doubt then it would be, is it possible to define an #Entity, with all the fields defined as the one I mentioned before and then have other entities to just update some fields, something like:
#Entity(tableName = "person")
data class PersonUpdateSurname{
#PrimaryKey
val id: Int,
val name:String
}
#Entity(tableName = "person")
data class PersonUpdateSurname{
#PrimaryKey
val id: Int,
val surname:String
}
Is there a way to tell Room which is the original table structure?
Is there a way to tell Room which is the original table structure?
This question is not clear. Maybe there is some misunderstanding you have.
Try to follow next schema:
There should be only one Person-related data class annotated with Room-annotations - #Entity, #PrimaryKey and so on. In your case it is Person class.
All the rest mentioned auxiliary classes should be just POJO (plain data classes), since they are not being persisted. In your case - PersonName and PersoneSurname (with the fields you described but without Room's annotations).
In DAO use entity-parameter in #Update:
#Update(entity = Person::class)
fun updateName(personName: PersonName)
#Update(entity = Person::class)
fun updateSurname(personeSurname: PersonSurname)
In your Repository call method what you need. If you want to update only name - you use method updateName() and instance of PersonName class as a parameter, for only surname's update - method updateSurname() and instance of class PersonSurname.

Android Room recursive relation

It's possible for room to have Recursive relations?
I have an Entity that can be nested in a Parent/Childs structures something like this
Category1
|_________Category2
|_________Category3
| |_________Category4
|_________Category5`
I'm copying this structure from a json that is obtained from a WebService.
This is my current Entity:
#Entity(tableName = "categories")
public class Category
{
#PrimaryKey
#NonNull
private String code;
private String name;
private String parentCode;
#Relation(parentColumn = "code", entityColumn = "parentCode", entity = Category.class)
private List<Category> childrens;
}
But during compiling I obtain a StackOverflow error:
Cause: java.lang.StackOverflowError
at android.arch.persistence.room.processor.PojoProcessor.doProcess(PojoProcessor.kt:113)
at android.arch.persistence.room.processor.PojoProcessor.access$doProcess(PojoProcessor.kt:74)
at android.arch.persistence.room.processor.PojoProcessor$process$1.invoke(PojoProcessor.kt:105)
at android.arch.persistence.room.processor.PojoProcessor$process$1.invoke(PojoProcessor.kt:74)
at android.arch.persistence.room.processor.cache.Cache$Bucket.get(Cache.kt:46)
I know that I can remove the children from the Entity and iterate the json to save every Category without childrens, and later get the children by the parent code in a separate query, but I just want to know if it is possible to have a recursive Relation like the one in the code
Short Answer: NO you can't have recursive relations.
Long Answer:
Reading the Docs about Relation in Room https://developer.android.com/reference/android/arch/persistence/room/Relation I found that you can't use #Relation annotation inside a class annotated as #Entity
Note that #Relation annotation can be used only in Pojo classes, an Entity class cannot have relations. This is a design decision to avoid common pitfalls in Entity setups. You can read more about it in the main Room documentation. When loading data, you can simply work around this limitation by creating Pojo classes that extend the Entity.

Is there any way to store Observable variables in Room persistance table?

I'm using Room library to save and retrieve data for my application. The model class User is having variables like - Observable name etc where Observable is RxJava class. But now gradle build is failing due to - error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
So I'm looking how can we save Observable variable to table?
I'm aware of type converters but unable to get how to do this. Like save String value from Observable to Database then convert it again to Observable when we get data from Database.
Any hints please?
You can do somthing like
#Entity(tableName = "my_table")
public class MyTable {
#ColumnInfo(name = "my_string_value")
public String myStringValue;
}
Then create your DAO
#Dao
public class MyTableDao {
#Query("select my_string_value from my_table limit 1 ")
Flowable<String> selectMyStringValue();
}
Flowable<String> flowable = myAppDataBase.getMyTableDao().selectMyStringValue();
I don't know why you want to save an Observable... but first of all you shouldn't .
To use the code from above you have to add the RxJava2 dependency because Flowable.

How to represent nested #Relation with Android Room?

Here is my POJO in kotlin:
data class Pass(var uuid: String,
var activationRestrictions:List<ActivationRestriction>)
data class ActivationRestriction(var uuid: String,
var activationRestrictionExceptions:List<ActivationRestrictionException>)
data class ActivationRestrictionException(var uuid: String)
How can I represent this nested relation with Room? Here is one of the solution, but it does not contain a nested relation. I am specifically looking for solving a nested relationship with Room.
You can use #Relation annotation for POJO classes.
A convenience annotation which can be used in a Pojo to automatically
fetch relation entities. When the Pojo is returned from a query, all
of its relations are also fetched by Room.
Here is the documentation.
Also, this answer has more details: Android Persistence room: "Cannot figure out how to read this field from a cursor"

Categories

Resources