Android Room: эффективный способ преобразования результата json в объект db - PullRequest
0 голосов
/ 03 октября 2018

Проблема

У меня POJO проанализирован из вызова API, который выглядит следующим образом

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.Но тогда мне пришлось бы создать новый объект и установить все значения вручную.
  • Сначала я думал, что преобразователи типов будут работать, но они, похоже, преобразуют отдельные столбцы.

Ответы [ 3 ]

0 голосов
/ 03 октября 2018

Все, что вам нужно сделать, это использовать @Embedded аннотацию для вашего POJO (класс модели), который будет ссылаться на другой класс.затем создайте класс преобразователя типов.

 @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;
}
0 голосов
/ 03 октября 2018

Согласно документации здесь «Количество классов Entity или 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 в виде столбца в моем Room Database, используя TypeConverters и один Dao.

Вы пытались использовать 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;
   }
}

Это относится к тому, что вы пробовали.Теперь перейдем к вашему утверждению «Я считаю, что мне нужно преобразовать объект в объект, соответствующий модели сущности базы данных».На самом деле, не обязательно.Вы можете использовать аннотацию @Ignore для различных экземпляров создания или реализаций вашей сущности, если есть хотя бы один конструктор по умолчанию, который включает primary key из entry.В вашем случае:

@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).Надеюсь, это поможет!

0 голосов
/ 03 октября 2018

Вы можете использовать @ Embedded аннотацию для вашего связанного POJO, который относится к другому классу.

Вы можете сделать это так:

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, для этого вам нужно использовать конвертер типов)

Ссылка от здесь

...