Have an error with Room:
someField has protected access in LibraryClass
I have no access to this field, because it's in library. How can I force Room to not save this field(because I don't need it)?
How can I force Room to not save this field
Don't inherit from that class. Having an #Entity inherit from some class that you do not control is fairly risky, and this is the sort of problem that you will encounter. Have your #Entity be a simple POJO.
Related
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.
By default, Room creates a column for each field that is defined in the entity. If an entity has fields that I don't want to persist, I have to use the #Ignore annotation.
This poses a problem with inheritance. Annotating all the unwanted fields from a base class becomes unfeasible at a certain point, especially if you have to make your own versions of complex stock objects only to ignore the fields.
Currently, I am using interfaces instead of inheritance to work around that problem, but I would prefer to have a base class for my Room objects.
Do you know a way to ignore fields by default, so I can rather De-Ignore the desired fields instead of the other way around? Preferably in Kotlin?
Edit:
I want to build a treeview of different room entities and it would be nice to have my treeview item as a base class for all of them. But the treeview item implements a lot of stuff, it is not practical to customize all of that just for #Ignore tags. There are workarounds, but i would need less code if i do it this way.
You can use #Ignore on your base classes as well, for instance:
open class MyBaseClass{
#Ignore
open var somethingBasic: Int = 0
}
#Entity(...)
class A : MyBaseClass{
var name: String? = null
}
#Entity(...)
class B : MyBaseClass{
var type: Int = 0
}
But be careful about this because using a base class for different tables is a bit abnormal and it's able to break all your tables somewhere (take migrations as an example). I suggest to take a deeper look on your structure and try to stay away from this :D
Are those two interchangable in context of Room database entity, or, if not, what are the differences between them?
#Ignore is a Room-specific annotation, saying that Room should ignore that field or method.
transient is a Java construct, indicating that this field should not be serialized in standard Java serialization. Room happens to treat this similarly to #Ignore by default. Mostly, that is there for cases where you are inheriting from some class that happens to use transient and you do not control that class (e.g., it is from a library).
For your own code, if you are not using Java serialization, I recommend sticking with #Ignore for the fields. transient is not an available keyword for a method, so to tell Room to ignore certain constructors, you have no choice but to use #Ignore.
Adding to CommonsWare's answer
transient is not good option for ignoring fields for Room as CommonsWare answered. It will create blocker when same modal is being used to parse data from server and store into database.
Let's assume you have a modal class MyModal.java as below
public static class MyModal {
#SerializedName(“intField”)
public int intField;
#SerializedName(“strField”)
public String strField;
#SerializedName(“booleanField”)
public boolean booleanField;
}
If you want to NOT SAVE booleanField into database, and if you modified that field as
transient : It will ignore this field while saving into database, BUT it will also ignore this field while parsing data which comes from server.
#Ignore : It will only ignore this field while inserting data into database, but this field will participate into json parsing.
I started using realm. it seemed to work fine, but I have some questions. When I use realm for simple object with primitive fields, everything is ok. But I'm facing issues using it for complex objects.
For example I have a class Passenger. It has several fields
Segment segment;
Documents documents;
....
Each field also has sub objects. Segment class
Flight flight;
Arrival arrival;
int pnrRequest;
So as I understand I will have several tables and I need one-to-many relations to connect this tables. What i want is to store passenger list inside database.
The problem is that I already have this classes as a model, but they dont extend RealmObject. I don't want to have duplicate classes one for model and one for database. Is there a way to avoid duplication of files and conversion from one model to another?
According to documentation it's posible:
An alternative to extending the RealmObject base class is implementing the RealmModel interface and adding the #RealmClass annotation.
Realm requires that all models that should be persisted must extend RealmObject or implement the interface RealmModel (see https://realm.io/docs/java/latest/#realmmodel-interface). If neither of these approaches work for you, you will need to duplicate the class and have conversion methods between them.
I have my app's networking code separated into a separate package. This package contains a POJO model that I'm serializing with Gson (using its #Expose annotation):
public class User {
#Expose
String username;
#Expose
String pathToAvatar;
// etc.
}
My app also is using ActiveAndroid as a database wrapper. I would like to extend the .networking.User model and add a couple more database-specific fields (secretKey or something) in my main logic. It would be nice if the networking code did not know its model was being used in a database. Unfortunately, I'm having to have .networking.User extend the ActiveAndroid Model base class (and having to label each networking variable with #Column). This works, with one problem: I'm getting a dummy User database table that corresponds with the networking code's class, even though it is not annotated with #Table, simply because it derives from Model. The main code's table is created correctly.
Can I prevent ActiveAndroid from creating a table when it finds a certain Model? Alternatively, is there a better way to approach this?