17

I am having a hard time getting a list item into room. the list item is called measurements and its of type Measurement. the list item has no primarykey that would be related to the database. but i have no problem adding the same primary key for the ProductModel if necessary.

Here is what i have so far:

@Entity(tableName = TABLE_NAME)
public class ProductModel {

    public static final String TABLE_NAME = "product";

    @PrimaryKey
    private int idProduct;

    private int idCategoryDefault;

    @Relation(parentColumn = "idProduct", entityColumn = "idProduct", entity = SortedAttribute.class)
    private List<SortedAttribute> sortedAttributes = null;
}

@Entity
public class SortedAttribute {

    @PrimaryKey
    private int idProduct;

    private String reference;

    @Embedded
    private List<Measurement> measurements = null; //****how do i get this into room ? its a LIST of measurements, not a measurement so calling Embedded i think wont work as it cant flatten it****/
}

public class Measurement {

    private String value;
    private String valueCm;

    public Measurement() {
    }
}
Devrim
  • 15,345
  • 4
  • 66
  • 74
j2emanue
  • 60,549
  • 65
  • 286
  • 456
  • Measurement needs a [TypeConverter](https://developer.android.com/reference/android/arch/persistence/room/TypeConverter.html) definition I guess. – Devrim Jun 29 '17 at 06:06

2 Answers2

36

Embedded annotation can be used on a POJO or Entity only, not for a List. So, Room can not automatically flatten your list in this case.
You can use TypeConverter to convert List<Measurement> into String(in JSON format) and vise versa. You can use any JSON parser library to support it. For example, I use Gson as following.

public class ProductTypeConverters {
    @TypeConverter
    public static List<Measurement> stringToMeasurements(String json) {
        Gson gson = new Gson();
        Type type = new TypeToken<List<Measurement>>() {}.getType();
        List<Measurement> measurements = gson.fromJson(json, type);
        return measurements;
    }

    @TypeConverter
    public static String measurementsToString(List<Measurement> list) {
        Gson gson = new Gson();
        Type type = new TypeToken<List<Measurement>>() {}.getType();
        String json = gson.toJson(list, type);
        return json;
    }
}

@Entity
@TypeConverters(ProductTypeConverter.class)
public class SortedAttribute {

    @PrimaryKey
    private int idProduct;

    private String reference;

    private List<Measurement> measurements = null; 
}
Quang Nguyen
  • 2,600
  • 2
  • 17
  • 24
  • if you read the accepted answer here https://stackoverflow.com/questions/44582397/android-room-persistent-library-typeconverter-error-of-error-cannot-figure-ou the author of the answer says converting from list is impossible. so i am confused. What do you think about the post ? – j2emanue Jun 29 '17 at 07:22
  • You surely are able to convert from a list. It just depends on how you encode it to supported type (for example `String`). You can check an example from `Google sample project`. https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/main/java/com/android/example/github/db/GithubTypeConverters.java – Quang Nguyen Jun 29 '17 at 09:00
  • when you say convert it to a string. how would i convert measurement to a string .could you give a example . do you mean i should return value + " " + measurement as string in the converter for example ? – j2emanue Jun 29 '17 at 10:18
  • The easiest way is that you convert it into JSON and store as a String. You can use GSON to encode and decode it. – Quang Nguyen Jun 29 '17 at 12:39
  • @QuangNguyen do you have an example how to convert into JSON and store as string and use GSON to encode or decode it? I will really appreciate it - you can make and update to your answer – K.Os Dec 14 '17 at 09:52
  • @QuangNguyen Thank you. However i have a problem with this in Kotlin, maybe you can help here? https://stackoverflow.com/questions/47823746/kotlin-convert-json-string-to-list-of-ojbect-using-gson – K.Os Dec 14 '17 at 23:37
  • On your question, there is already an answer from other. Check it out first. – Quang Nguyen Dec 15 '17 at 01:32
  • How should I handle the exception thrown by `fromJson`? Do I return an empty list? – jL4 Jan 16 '18 at 19:25
  • 1
    It is better to throw a runtime exception as I think. And you can write unit tests for the converter to make sure it handles conversion correctly. – Quang Nguyen Jan 17 '18 at 07:49
  • Error:Entities and Pojos must have a usable public constructor. You can have an empty constructor or a constructor whose parameters match the fields (by name and type). issue comes – Android Surya Oct 31 '18 at 12:55
  • This is more of a hack not a solution... It's not very efficient to convert a list to json and store it in another column. – Sergio Dec 28 '20 at 14:44
4

EDIT: Use a type converter

@Relation is what you are looking for.

https://developer.android.com/reference/android/arch/persistence/room/Relation.html

From the Room docs:

@Entity
public class Pet {
     @ PrimaryKey
     int petId;
     String name;
 }
 public class UserNameAndAllPets {
   public int userId;
   public String name;
   @Relation(parentColumn = "petId", entityColumn = "userId")
   public List<Pet> pets;
 }

 @Dao
 public interface UserPetDao {
     @Query("SELECT petId, name from User")
     public List<UserNameAndAllPets> loadUserAndPets();
 }

Note: Upon further research, Room does not quite support lists of objects that are INSIDE objects. I (and others) have opted to handle the lists separately. Room can handle lists of objects just fine as long as they aren't within an object; so as long as your items inside the list are related to your overall object you can recover the list.

So, you would actually @Ignore the list and just handle it in your Dao abstract class. I could not find the SO post's I found earlier that portray this.

DeaMon1
  • 572
  • 5
  • 10