Android Room recursive relation - android

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.

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 database with list inside an object

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.

Handling Entities and Pojos

Still new to Room and while most of the tutorials I've found are related to simple table and CRUD operations I am stuck on evolving this.
Let's take this sample structures.
Users entity
#Entity(tableName = "users")
public class UsersEntity{
#PrimaryKey(autoGenerate = true)
private long id;
#NonNull
private String name;
#NonNull
private long roleId;
}
Roles entity
#Entity(tableName = "roles")
public class RolesEntity{
#PrimaryKey(autoGenerate = true)
private long id;
#NonNull
private String name;
}
First question: Should Entity objects be extended to also replace POJO? Or have Entities and POJO as separate classes?
Extending from the Room setup, the way I would see User POJO is:
public class User{
private long id;
private Role role;
}
Basically this setup should work both if the User would come as a json response from a web service or entered by the user in the app's input fields.
However, this raises the second question: how to insert and retrieve user info?.
Inserting seems possible as there could be something like
userDAO.insertRole(userId)
But how can I get the Role object of User by using Room and the userDAO?
I find inappropriate to do something like:
user = userDao.getUser(userId)
user.setRole(roleDao.getRole(user.getRoleId)
Third question: it seems to be a good practice to have the table columns with _ (eg. role_id) but in java roleId is recommended as class property. If the result of a #Query for instance select role_id from... and the the POJO with roleId field, will fail so the query needs to be select role_id as roleId... to get it work. Is it a good practice to use camel case in table/column names in sqlite?
What you intend as POJO, probably can be seen as a kind of a view model. In general it is a bad idea to unify/link entities and pojos because you are just making a long wider visibilty/scope for the entity, where it is not necessary and can lead to potential problems.
Say you have some client which requires some different visualization of the data, for instance imagine you have a website which exposes a vehicle data and you have implemented everything using metric system, so for distance you have km, for speed km/h and so on. Now your company gains a huge client from UK, and they want you to provide them the data in imperial format. What to do now? Probably implement a deserilization/conversion process which takes the values and converts them according to the context of the user (whether they are using metric or imperial system). What could possibly go wrong if your entity and view model objects are basically the same? Really bad stuff. You have really tight coupling of things, you should implement different getters for serialization for client, for db..it can become a mess.
Instead if you separate the two, you will have your entity which takes care of working with the database, which is standard procedure with small coefficient of variability, and on the other side you will have the view model which is very likely to require frequent modification, after all it is expected, since it is the interface to the final user.

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.

Android Room Database Nested Object Reference for array of objects

I have a class structure with
Class x {
int a;
int b;
Y[] yList;
}
Class Y {
int m;
int n;
}
I am using data binding, Room and Dagger. I am getting compilation error as 'cannot find class DatabindingComponent', possibly because Room doesn't allow persistent of Nested objects. To enable I used #Embedded annotation but still getting same error. But if I use #Ignore annotation indicating Room that do not process this field; compilation is happening successfully.
How to reference nested array of objects for Room Database without foreign key?
Please refer to
https://developer.android.com/topic/libraries/architecture/room.html#no-object-references
https://developer.android.com/reference/android/arch/persistence/room/Ignore.html
https://developer.android.com/reference/android/arch/persistence/room/Embedded.html.
How to reference nested array of objects for Room Database without foreign key?
If you do not want Y to be an #Entity with its own table, the only option that I know of is to use #TypeConverters:
Define two static methods with #TypeConverter that convert Y[] to and from some basic type (e.g., String, by using JSON)
Register the class holding those methods using #TypeConverters somewhere (e.g., on your RoomDatabase subclass)
This works using collection classes (e.g., List, Set). I would guess that it works with Java arrays (Y[]), though I have not tried it.

Categories

Resources