Android Room:将 json 结果转换为 db 对象的有效方法
Posted
技术标签:
【中文标题】Android Room:将 json 结果转换为 db 对象的有效方法【英文标题】:Android Room: Efficient way to transform json result into db object 【发布时间】:2019-03-08 05:58:09 【问题描述】:问题
我有一个从 API 调用解析出来的 POJO,看起来像这样
public class Article
public Long id;
@Expose
@SerializedName("section")
public String section;
@Expose
@SerializedName("title")
public String title;
@Expose
@SerializedName("topics")
public List<String> topics;
@Expose
@SerializedName("media")
public List<Media> media;
为了尽量减少冗余和重复,我希望创建这样的架构
@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 Articles
@PrimaryKey
public Long articleId;
@ColumnInfo(name = "topic_id")
public Long topicId;
@ColumnInfo(name = "media_id")
public Long mediaId;
@Entity
public class Article
// Left out
@Entity
public class Media
// Left out
如您所见,当我调用 DAO 方法访问数据库时,我不能直接传入 pojo 对象(除非我弄错了)。我相信我需要将对象转换为与数据库实体模型匹配的对象。
问题
android 框架是否提供了一种从 POJO 转换为数据库模型对象的自然方式?除了自己手动转换之外,还有其他方法吗?
我尝试过的事情
我知道我可以在我的 DAO 接口中的方法内实现转换。但是我必须创建一个新对象并手动设置所有值。 我最初认为类型转换器可以工作,但它们似乎可以转换单个列。【问题讨论】:
只需创建一个类型转换器类。 【参考方案1】:您所要做的就是为您的 POJO(Model Class) 使用 @Embedded
注释,它将引用另一个类。然后创建一个类型转换器类。
@Embedded(prefix = "media")
private Meida 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 fromArrayLisr(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;
【讨论】:
我可以看到 typeconverters 确实简化了这个过程。但是它如何处理我需要从“主题”之类的列表类型对象中查询的情况。如果我想获取某个主题的所有文章怎么办?如果我将“主题”分成它自己的实体,我相信我可以通过选择和连接查询来做到这一点。如果我使用类型转换器,它仍然有效吗? 我认为您不能使用DAO
中的查询来注释作为其中一列中的值保存的列表。您可能必须选择每个列表并 for/while 循环要匹配的值。您可以通过一些创造性的@Query
语句匹配使用TypeConverters
的特定对象,例如:@Query("Select article_entry Where media = :mediaItem) abstract void loadArticleByMediaItem(Media mediaItem);
在你道中只需使用查询即可。 @Query("SELECT * FROM topic where topic.topic LIKE :topic") ListTypeConverters
,我还没有尝试过,但我认为它对你有用
刚刚阅读了另一个 *** 帖子。该查询有效,因为它在转换后的主题字符串中搜索相似主题。我将使用类型转换器。感谢您的帮助!【参考方案2】:
您可以对引用另一个类的相关 POJO 使用 @Embedded 注释。
你可以这样做:
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;
那么现在,您可以直接将这个 POJO 用作 ROOM 的实体。
请注意:
虽然我不确定你将如何处理这种关系(因为 Media obj 在 Article 类的列表中,你需要为此使用类型转换器)
来自here的参考
【讨论】:
【参考方案3】:根据文档here“实体或道类的数量没有限制,但它们在数据库中必须是唯一的。”所以我认为您可以简单地在扩展RoomDatabase
的数据库类中声明不同的类。
您是否尝试过简单地将不同的 POJO 声明为不同的实体并将它们全部包含在同一个数据库类中?
例如:
// 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();
这可能对冗余没有帮助,但我最初的想法也是类型转换器。实际上,我什至使用TypeConverters
和单个Dao
成功地将parcelable
对象作为我的Room Database
中的列实现。
您是否尝试过在您的TypeConverter
课程中使用Gson
?我相信this article 更直接地解决了您的问题。它是在房间数据库中存储对象的指南。同样,诀窍在于类型转换器并将您的对象声明为 Gson 的类型标记。例如:
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;
这解决了您尝试过的事情。现在开始您的陈述“我相信我需要将对象转换为与数据库实体模型匹配的对象。”其实,不一定。您可以将@Ignore
注解用于您的实体的不同创建实例或实现,只要至少有一个默认构造函数包含entry
的primary key
。在你的情况下:
@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...
如果您像上面一样创建ArticlesEntry
,则需要创建并包含不同的TypeConverters
,它们都可以在同一个类中并使用@TypeConverters(MyConverters.class)
导入到特定的数据库中。希望这会有所帮助!
【讨论】:
以上是关于Android Room:将 json 结果转换为 db 对象的有效方法的主要内容,如果未能解决你的问题,请参考以下文章
Android Room 不确定如何将光标转换为方法的返回类型问题
Android:将 Json 对象转换为 Strings.xml
在 Android 中将 MySql 查询转换为 SQL Room 查询 - kotlin
如何在 ROOM android 中修复“不确定如何将光标转换为此方法的返回类型”