Basically, there are two things I don't understand: objects with objects and objects with lists of objects
Say I receive a list of objects from the server. Each of them looks like this:
@Entity
public class BigObject {
@PrimaryKey
private int id;
private User user;
private List<SmallObject> smallObjects;
}
with these two objects as fields:
@Entity
public class User {
@PrimaryKey
private int id;
private String name;
@TypeConverters(GenderConverter.class)
public MyEnums.Gender gender;
}
@Entity
public class SmallObject {
@PrimaryKey (autoGenerate = true)
private int id;
private String smallValue;
}
They are more complicated than this, so I can't use @TypeConverters as Room suggests:
error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
How do I store this data structure in Room?
Convert Object/ List<Object> to String and then, Store it. You can store the objects in Room Library as String. For that, you can serialize the object and store it as String in the Room Database.
Room is a Database Object Mapping library that makes it easy to access database on Android applications. Rather than hiding the details of SQLite, Room tries to embrace them by providing convenient APIs to query the database and also verify such queries at compile time.
What is a Room database? Room is a database layer on top of an SQLite database. Room takes care of mundane tasks that you used to handle with an SQLiteOpenHelper . Room uses the DAO to issue queries to its database. By default, to avoid poor UI performance, Room doesn't allow you to issue queries on the main thread.
I think the best way to answer this is a breif overview in storing structures...
Lists
Room does not support storing lists that are nested inside of a POJO. The recommended way to store lists is to use the foreign key approach. Store the List of objects in a seperate table (in this case a smallObjects table) with a foreign key to their related parent object (in this case "big_object_id"). It should look something like this...
@Entity
public class BigObject {
@PrimaryKey
private int id;
private User user;
@Ignore
private List<SmallObject> smallObjects;
}
@Entity(foreignKeys = {
@ForeignKey(
entity = BigObject.class,
parentColumns = "id",
childColumns = "big_object_fk"
)})
public class SmallObject {
@PrimaryKey (autoGenerate = true)
private int id;
private String smallValue;
@ColumnInfo(name = "big_object_fk")
private int bigObjectIdFk
}
Note that we have added the @Ignore
annotaiton to List<SmallObject>
as we want to ignore the field during Room persistance (as lists are not supported). It now exists so that when we request our list of related small objects from the DB we can still store them in the POJO.
To my knowledge this will mean you are making two queries.
BigObject b = db.BigObjectDao.findById(bOId);
List<SmallObject> s = db.smallObjectDao.findAllSOforBO(bOId);
b.setsmallObjects(s);
It appears that there is a short hand for this in the form of @Relation
Type Converters
These are for cases where you have a complex data structure that can be flattend without losing information, and stored in a single column. A good example of this is the Date object. A Date object is complex and holds a lot of values, so storing it in the database is tricky. We use a type converter to extract the milli representation of a date object and store that. We then convert the millis to a date object on the way out thus keeping our data intact.
Embedded
This is used when you want to take the fields of all nested POJOs in your parent POJO and flatten them out to store in one table. an example :
- name
- age
- location
- x
- y
- DOB
..when embedded this structure would be stored in the database as :
- name
- age
- location_x
- location_y
- DOB
In a sense Embedded exists to save you time creating type converters for every nested object that contains primary type fields like String, int, float, etc...
List<Object>
to String and then, Store it.You can store the objects in Room Library as String. For that, you can serialize the object and store it as String in the Room Database.
Store to Room
Object -> Serialize -> String -> Store
Read from Room
String -> Deserialize ->Object -> Read
There are many options available. You can either do it manually or you can use a library for this. You can use Google's GSON library. It is pretty easy to use.
Code: Object -> String
public String stringFromObject(List<YourClass> list){
Gson gson = new Gson();
String jsonString = gson.toJson(list);
return jsonString;
}
Code: String-> Object
public List<YourClass> getObjectFromString(String jsonString){
Type listType = new TypeToken<ArrayList<YourClass>>(){}.getType();
List<YourClass> list = new Gson().fromJson(jsonString, listType);
return list;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With