How to fill non column field of entity in room library

Viewed 6597

I have a class entity as below

@Entity
public class Task {    
    private String name; 
    private Integer ParentId;
    private Integer userId;   
    @Ignore
    private int noOfSubTask;
}

in DAO class there is a method getTaskList()

@Dao
public interface TaskDao extends Dao<Task> {

@Query("SELECT *,(SELECT count(*) FROM Task b  WHERE a._id = b.ParentId ) AS noOfSubTask FROM Task a ")
LiveData<List<Task>> getTaskList();
}

I want to fill noOfSubTask with the number given by (SELECT count(*) FROM Task b WHERE a._id = b.ParentId ) portion of query, but problem is it is not a column so room library does not map it getTaskList method in dao implementation (auto-generated) class.

Is there any way to fill non column field of entity (like noOfSubTask in my case) using any method of dao class of room library?

4 Answers

I faced the same problem a few days ago and had a look at this thread. I am using Kotlin data classes for creating database entities. Given that Kotlin data classes do not play well with inheritance subclassing was not a viable option. My solution was to use the @Embedded keyword in a wrapping class, as follows:

data class TaskToDisplay(@Embedded
                         var task: Task,
                         var noOfSubTask: Int = 0)

This solution does not create an additional column in the database and most importantly matches all Task's fields with Room's response columns.

Create a sub class of Task suppose

public class TaskDisplayModel extends Task{

@Ignore
private transient int noOfSubTask;

}

Then your query will be

@Query("SELECT *,(SELECT count(*) FROM Task b  WHERE a._id = b.ParentId ) AS noOfSubTask FROM Task a ")
LiveData<List<TaskDisplayModel >> getTaskList();

You should move the @Ignore field outside of the constructor, like this:

Sample data:

@Entity(primaryKeys = ["id"])
data class User(
    @SerializedName("id")
    val id: Int,

    @SerializedName("name")
    val name: String,

    @SerializedName("age")
    val age: Int
) {
   @Ignore
   val testme: String?
}

Refer github discussion for more details

I'm using Kotlin and I've had a similar problem, and below is how I solved it.

  1. Add additional field with ?(question mark) for nullable, without @Ignore annotation

    @Entity(tableName = "task")
    data class Task (
        val name: String,
        val parentId: Integer,
        val userId: Integer,
        val noOfSubTask: Integer?
    )
    
  2. Add additional field(noOfSubTask in this case) to every query that selects Task in DAO.

    @Dao
    interface TaskDao {
        @Query("SELECT *,(SELECT count(*) FROM Task b  WHERE a._id = b.ParentId ) AS noOfSubTask FROM Task a ")
        fun getTaskList(): LiveData<List<Task>>
    
        @Query("SELECT *, NULL AS noOfSubTask FROM Task WHERE name = :name")
        fun getTask(name: String): LiveData<Task>
    
        ...
    }
    

If this does not work, you can try RawQuery that was recently introduced in Google I/O 2018.

Related