Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to store objects in Android Room?

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?

like image 736
ildar ishalin Avatar asked Jun 24 '17 12:06

ildar ishalin


People also ask

How do you save an object in a room database?

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.

What is the use of room in Android?

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 Android room database?

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.


2 Answers

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...

like image 53
Jack Dalton Avatar answered Oct 18 '22 05:10

Jack Dalton


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.

Store to Room

Object -> Serialize -> String -> Store

Read from Room

String -> Deserialize ->Object -> Read

How to Serialize/Deserialize?

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;

}
like image 4
Rohit Singh Avatar answered Oct 18 '22 04:10

Rohit Singh