Home > database >  Room Android, select on two tables
Room Android, select on two tables

Time:10-20

I am new to Room and I'm struggling with it. I would like to do a simple select over two tables named Project and Tasks. These are the two classes and a third to link them :


    @Entity
    public class Project {
        @PrimaryKey(autoGenerate = true)
        private final long id;
        @NonNull
        private final String name;
        @ColorInt
        private final Integer color;
       }
    
    @Entity(foreignKeys = @ForeignKey(entity = Project.class, parentColumns = "id", childColumns = "projectId"))
    public class Task {
    
        @PrimaryKey(autoGenerate = true)
        private long idTask;
    
        // clé commune
        private long projectId;
    
        @NonNull
        private String nameTask;
    
        public long creationTimestamp;
    // constructor, getters, setters
       }
    
    public class TaskWithProject {
        @Embedded public Project project;
        @Relation(parentColumn = "id", entityColumn = "projectId")
        public Task task;
    }

I have tried many things in my Dao class. Here are two of those :


    @Dao
    public interface TaskDao {
    (...)
    
    // Solution 1
    @Query("SELECT * FROM Task t JOIN Project p ON t.projectId = p.id")
        LiveData<List<TaskWithProject>> getTaskWithProject();
    
    // Solution 2 from https://developer.android.com/training/data-storage/room/relationships
    @Transaction
    @Query("SELECT * FROM Task")
    LiveData<List<TaskWithProject>> getTaskWithProject();

My database is populated with these datas (no problem in the database inspector) :


    projectDao.insertProject(new Project(0, "Projet Tartampion", 0xFFEADAD1));
                    projectDao.insertProject(new Project(0, "Projet Lucidia", 0xFFB4CDBA));
                    projectDao.insertProject(new Project(0, "Projet "   "Circus", 0xFFA3CED2));
                    taskDao.insertTask(new Task(0, 1, "Task 1 - Tartampion"));
                    taskDao.insertTask(new Task(0, 1, "Task 2 - Tartampion"));
                    taskDao.insertTask(new Task(0, 2, "Task 1 - Lucidia"));

I get the data with this function :


    public LiveData<List<TaskViewStateItem>> getAllTasks() {
            return Transformations.map(repository.getTaskWithProject(), tasks -> {
                List<TaskViewStateItem> liststateitems = new ArrayList<>();
                    for (TaskWithProject t : tasks) {
                        Log.i(TAG, "getAllTasks: "  t.toString());
                        liststateitems.add(new TaskViewStateItem(t.task.getIdTask(), t.task.getNameTask(), t.project.getName(), t.project.getColor(), t.task.getCreationTimestamp()));
                    }
                }
                return liststateitems;
            });
        }

With the solution 1 above I have 3 entries as expected but with a duplicate one.


    I/Log ViewModel: getAllTasks: TaskWithProject{project=Project{id=1, name='Projet Tartampion', color=-1385775}, task=Task{idTask=2, projectId=1, nameTask='Task 2 - Tartampion', creationTimestamp=1634723235}}
    I/Log ViewModel: getAllTasks: TaskWithProject{project=Project{id=1, name='Projet Tartampion', color=-1385775}, task=Task{idTask=2, projectId=1, nameTask='Task 2 - Tartampion', creationTimestamp=1634723235}}
        getAllTasks: TaskWithProject{project=Project{id=2, name='Projet Lucidia', color=-4928070}, task=Task{idTask=3, projectId=2, nameTask='Task 1 - Lucidia', creationTimestamp=1634723235}}

The solution 2 does not compile


    error: Not sure how to convert a Cursor to this method's return type (com.cleanup.todoc.model.TaskWithProject).
        LiveData<List<TaskWithProject>> getTaskWithProject();
                                        ^

I have no idea what I did wrong. So thank you very much for any help you can give me

CodePudding user response:

As your TaskWithProject class has the project embedded, then it expects, to get the columns for the project and then build the task(s) from that and hence when you use SELECT * FROM Task it doesn't have the pertinent columns (with the join it does BUT may not work as expected).

  • really TaskWithProject is ProjectWithTask.

So either use SELECT * FROM project or use a POJO with the Task Embedded and the Project as the @Relation (with SELECT * FROM task).

  • Related