web-dev-qa-db-ja.com

Android Room:jsonの結果をdbオブジェクトに変換する効率的な方法

問題

次のような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 FrameworkはPOJOからデータベースモデルオブジェクトに変換する自然な方法を提供していますか?手動で変換する以外にこれを行う方法はありますか?

私が試したもの

  • DAOインターフェイス内のメソッド内に変換を実装できることを知っています。ただし、新しいオブジェクトを作成し、すべての値を手動で設定する必要があります。
  • 私は当初、typeconvertersは機能すると思っていましたが、個々の列を変換するようです。
11
Kevin.Lam

あなたがしなければならないすべては使用@Embedded別のクラスを参照するPOJO(Model Class)の注釈。次に、型コンバータークラスを作成します。

 @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;
}
3
Atif AbbAsi

別のクラスを参照する関連する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 [〜#〜]のエンティティとして使用できます[〜#〜]部屋[〜#〜]


ご注意ください:

その関係をどのように処理するかはわかりませんが(Media objはArticleクラスのリストにあるため、そのために型コンバーターを使用する必要があります)

ここ からの参照

1
Jeel Vankhede

ドキュメントによると here 「エンティティまたはDaoクラスの数に制限はありませんが、データベース内で一意である必要があります。」したがって、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();
}

これは厳密には冗長性に役立ちませんが、私の最初の考えは型コンバーターでもあると思います。 parcelableと単一のTypeConvertersを使用して、DaoオブジェクトをRoom Database内の列として実際に実装することもできました。

GsonクラスでTypeConverterを使用してみましたか?私は この記事 があなたの質問にもっと直接対処すると信じています。部屋のデータベースにオブジェクトを保存するためのガイドです。繰り返しますが、コツは型コンバーターと、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;
   }
}

それはあなたが試したことに対処します。次に、「オブジェクトをデータベースエンティティモデルに一致するオブジェクトに変換する必要があると思います」というステートメントに移ります。実際には、必ずしもそうではありません。 entry@Ignoreを含むデフォルトのコンストラクタが少なくとも1つある限り、エンティティのさまざまな作成インスタンスまたは実装に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)を使用して特定のDBにインポートできます。 。お役に立てれば!

1
Mr.Drew