web-dev-qa-db-fra.com

Android Room: moyen efficace de transformer le résultat json en objet db

Problème

J'ai un POJO analysé à partir d'un appel API qui ressemble à ceci

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;
}

Pour minimiser la redondance et les doublons, je cherche à créer un schéma comme celui-ci

@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
}

Comme vous pouvez le voir, lorsque j'appelle les méthodes DAO pour accéder à la base de données, je ne peux pas simplement passer directement l'objet pojo (sauf si je me trompe). Je crois que je dois transformer l'objet en un qui correspond au modèle d'entité de base de données.

Question

Le framework Android fournit-il un moyen naturel de convertir de POJO en objet de modèle de base de données? Existe-t-il un moyen de le faire autre que de le convertir manuellement moi-même?

Choses que j'ai essayées

  • Je sais que je peux implémenter la conversion à l'intérieur d'une méthode dans mon interface DAO. Mais alors je devrais créer un nouvel objet et définir toutes les valeurs manuellement.
  • Au départ, je pensais que les convertisseurs de types fonctionneraient, mais ils semblent convertir des colonnes individuelles.
11
Kevin.Lam

Tout ce que vous avez à faire est d'utiliser @Embedded annotation pour votre POJO (classe de modèle) qui fera référence à une autre classe. puis créez une classe de convertisseur de type.

 @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

Vous pouvez utiliser @ Annotation intégrée pour votre POJO associé qui fait référence à une autre classe.

Vous pouvez faire comme ça:

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;
}

Alors maintenant, vous pouvez directement utiliser ce [~ # ~] pojo [~ # ~] comme entité pour [~ # ~] chambre [~ # ~] .


Veuillez noter:

Bien que je ne sois pas sûr de la façon dont vous allez gérer cette relation (car, Media obj est dans la liste pour la classe Article, vous devrez utiliser le convertisseur de type pour cela)

Référence de ici

1
Jeel Vankhede

Selon la documentation ici "Il n'y a pas de limite au nombre de classes Entity ou Dao mais elles doivent être uniques dans la base de données." Je pense donc que vous pouvez simplement déclarer les différentes classes de votre classe de base de données qui étend RoomDatabase.

Avez-vous essayé de simplement déclarer les différents POJO en tant qu'entités différentes et de les inclure tous dans la même classe de base de données?

Par exemple:

  // 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();
}

Cela peut ne pas aider exactement à la redondance, mais ma pensée initiale serait également les convertisseurs de type. J'ai même réussi à implémenter un objet parcelable en tant que colonne dans mon Room Database En utilisant TypeConverters et un seul Dao.

Avez-vous essayé d'utiliser Gson dans votre classe TypeConverter? Je crois que cet article répond plus directement à votre question. C'est un guide pour stocker des objets dans une base de données de pièce. Encore une fois, l'astuce réside dans les convertisseurs de type et la déclaration de votre objet comme jeton de type pour Gson. Par exemple:

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;
   }
}

Cela répond aux choses que vous avez essayées. Passons maintenant à votre déclaration "Je crois que je dois transformer l'objet en un objet qui correspond au modèle d'entité de base de données." En fait, pas nécessairement. Vous pouvez utiliser l'annotation @Ignore Pour différentes instances de création ou implémentations de votre entité, tant qu'il existe au moins un constructeur par défaut qui inclut le primary key Du entry. Dans ton cas:

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

}

Si vous créez votre ArticlesEntry comme ci-dessus, vous devrez créer et inclure les différents TypeConverters, qui peuvent tous être dans la même classe et importés dans la base de données spécifique avec @TypeConverters(MyConverters.class). J'espère que cela t'aides!

1
Mr.Drew