Android Room: Efficient way to transform json result into db object
According to the documentation here "There is no limit on the number of Entity or Dao classes but they must be unique within the Database." So I think you can simply declare the different classes within your database class that extends RoomDatabase
.
Have you tried simply declaring the different POJOs as different entities and including them all in the same database class?
For instance:
// Article, Topic and Media are classes annotated with @Entity.
@Database(version = 1, entities = {Article.class, Topic.class, Media.class})
abstract class MyDatabase extends RoomDatabase {
// ArticleDao is a class annotated with @Dao.
abstract public ArticleDao articleDao();
// TopicDao is a class annotated with @Dao.
abstract public TopicDao topicDao();
// MediaDao is a class annotated with @Dao.
abstract public MediaDao mediaDao();
}
This may not exactly help with the redundancy, but my initial thought would be type converters as well. I've actually successfully even implemented a parcelable
object as a column within my Room Database
using TypeConverters
and a single Dao
.
Have you tried using Gson
in your TypeConverter
class? I believe this article addresses your question more directly. It's a guide to storing objects in a room database. Again, the trick is in the type converters and declaring your object as the type token for Gson. For instance:
public class Converters {
@TypeConverter
public static List<Media> fromStringToList(String mediaListString) {
Type myType = new TypeToken<List<Media>>() {}.getType();
return new Gson().fromJson(mediaListString, myType);
}
@TypeConverter
public static String fromMediaListToString(List<Media> mediaItems) {
if (mediaItems== null || mediaItems.size() == 0) {
return (null);
}
Gson gson = new Gson();
Type type = new TypeToken<List<VideoParcelable>>() {
}.getType();
String json = gson.toJson(mediaItems, type);
return json;
}
}
That addresses the things you've tried. Now on to your statement "I believe I need to transform the object to one which matches the database entity model." Actually, not necessarily. You can use the @Ignore
annotation for different creation instances or implementations of your entity, so long as there is at least one default constructor that includes the primary key
of the entry
. In your case:
@Entity(foreignKeys = {
@ForeignKey(entity = Article.class, parentColumns = "id", childColumns =
"articleId"),
@ForeignKey(entity = Topic.class, parentColumns = "id", childColumns =
"topicId"),
@ForeignKey(entity = Media.class, parentColumns = "id", childColumns =
"mediaId")
}
public class ArticlesEntry {
@PrimaryKey
public Long articleId;
@ColumnInfo(name = "topic_id")
public Long topicId;
@ColumnInfo(name = "media_id")
public Long mediaId;
private Article articleObject;
private Media mediaObject;
//default constructor
public ArticlesEntry(int id) {
this.articleId = id;
}
//You can call this anytime you add to the database with media object input
@Ignore
public ArticlesEntry(int id, Media inMedia) {
this.articleId = id;
this.mediaObject= inMedia;
}
//You can create many of these and insert as needed, the left out variables of the
//are null, note that id has to be passed b/c your primary key isn't set to
//autogenerate
@Ignore
public ArticlesEntry(int id, Article inArticle) {
this.articleId = id;
this.articleObject= articleObject;
}
//Or both objects:
@Ignore
public ArticlesEntry(int id, Media inMedia, Article inArticle) {
this.articleId = id;
this.mediaObject = inMedia;
this.articleObject= articleObject;
}
//getters and setters here...
}
If you create your ArticlesEntry
like above, you'll need to make and include the different TypeConverters
, which can all be within the same class and imported to the specific DB with @TypeConverters(MyConverters.class)
. Hope this helps!
All you have to do is use @Embedded
annotation for your POJO(Model Class) which will refer to another class. then create a type converter class.
@Embedded(prefix = "media")
private Media media;
@TypeConverters({TypeConvertorClass.class})
@Database(entities = {Article .class,Media.class}, version = 1, exportSchema = false)
public abstract class `DataBaseExample` extends RoomDatabase {
}
public class Converters {
@TypeConverter
public static ArrayList<String> fromString(String value) {
Type listType = new TypeToken<ArrayList<String>>() {}.getType();
return new Gson().fromJson(value, listType);
}
@TypeConverter
public static String fromArrayList(ArrayList<String> list) {
Gson gson = new Gson();
String json = gson.toJson(list);
return json;
}
}
public class TypeConvertorClass {
@TypeConverter
public static Media getMedia(String longId) {
return longId== null ? null : new Meida();
}
}
@Entity(tableName = "Article")
public class Article {
@ColumnInfo (name = "article_id")
public Long id;
@Expose
@SerializedName("section")
public String section;
@Expose
@SerializedName("title")
public String title;
@Expose
@SerializedName("topics")
public List<String> topics;
@Embedded(prefix = "media") // We need relation to Media table
@Expose
@SerializedName("media")
public List<Media> media;
}
public class Media {
@ColumnInfo (name = "media_id")
public Long id;
}
You can use @Embedded annotation for your related POJO which refers to another class.
You can do like this:
Article.java
@Entity(tableName = "Article")
public class Article {
@ColumnInfo (name = "article_id")
public Long id;
@Expose
@SerializedName("section")
public String section;
@Expose
@SerializedName("title")
public String title;
@Expose
@SerializedName("topics")
public List<String> topics;
@Embedded // We need relation to Media table
@Expose
@SerializedName("media")
public List<Media> media;
}
Media.java
public class Media {
@ColumnInfo (name = "media_id")
public Long id;
}
So now on, you can directly use this POJO as Entity for ROOM.
Please note:
Though i'm not sure about how you'll handle that relation (because, Media obj is in list for Article class, you'll need to use type converter for that)
Reference from here