agrosner / DBFlow

A blazing fast, powerful, and very simple ORM android database library that writes database code for you.
MIT License
4.87k stars 598 forks source link

Bug in BaseMigration class and JOIN #1359

Closed Chezlui closed 6 years ago

Chezlui commented 7 years ago

DBFlow Version: 4.0.4 Bug: Weird behaviour while migrating and using JOIN.

Description: Hi, I'm extending BaseMigration to populate a column that I've added previously to a table. Basically, I have two tables, Questions and Exams, so I want to find all the Questions belonging to Exams that are finished (Consider 4 exams with 10 questions each, 2 exams are finished).

(for any reason indentation is not working here, you can see this code again down below)

          List<QuestionsExam> questionsExams = SQLite.select()
                    .from(QuestionsExam.class).as("Q")
                    .join(es.quizit.models.Exam.class, Join.JoinType.LEFT_OUTER).as("E")
                    .on(QuestionsExam_Table.examId.withTable(NameAlias.builder("Q").build())
                            .eq(Exam_Table._id.withTable(NameAlias.builder("E").build()))
                    )
                    .where(Exam_Table.isEnded.withTable(NameAlias.builder("E").build()).eq(true))
                    .queryList(database);   // Use the wrapper instead of no arguments to ensure the same ddbb is not called twice

This, as expected, is returning a list with 20 questions, so now I iterate in those quetions objects to modify a value and save them back in the database:

            for(QuestionsExam questionsExam : questionsExams) {
                questionsExam.setAnswerLocked(true);
                questionsExam.save(database);
                Log.d("DDBB", questionsExam.toString());
            }

I repeat the same procedure but for unfinished exams, in total 40 questions and 4 exams.

But when I check the QuestionsExam table, only 4 items have been modified. I repeated this process with 270 questions and 10 exams and only 10 questions looked modified after the process. It looks like the database gets in some weird state after the JOIN, because the saving process is done after the JOIN.

The full code for convenience is here:

    @Migration(version = 8, database = MyDatabase.class, priority = 1)
    public static class Migration2populate extends BaseMigration {

        @Override
        public void migrate(@NonNull DatabaseWrapper database) {
            List<QuestionsExam> questionsExams = SQLite.select()
                    .from(QuestionsExam.class).as("Q")
                    .join(es.quizit.models.Exam.class, Join.JoinType.LEFT_OUTER).as("E")
                    .on(QuestionsExam_Table.examId.withTable(NameAlias.builder("Q").build())
                            .eq(Exam_Table._id.withTable(NameAlias.builder("E").build()))
                    )
                    .where(Exam_Table.isEnded.withTable(NameAlias.builder("E").build()).eq(true))
                    .queryList(database);   // Use the wrapper instead of no arguments to ensure the same ddbb is not called twice

            for(QuestionsExam questionsExam : questionsExams) {
                questionsExam.setAnswerLocked(true);
                questionsExam.save(database);
                Log.d("DDBB", questionsExam.toString());
            }

            questionsExams = SQLite.select()
                    .from(QuestionsExam.class).as("Q")
                    .join(es.quizit.models.Exam.class, Join.JoinType.LEFT_OUTER).as("E")
                    .on(QuestionsExam_Table.examId.withTable(NameAlias.builder("Q").build())
                            .eq(Exam_Table._id.withTable(NameAlias.builder("E").build()))
                    )
                    .where(Exam_Table.isEnded.withTable(NameAlias.builder("E").build()).eq(false))
                    .queryList(database);

            for(QuestionsExam questionsExam : questionsExams) {
                questionsExam.setAnswerLocked(false);
                questionsExam.save(database);
            }

        }
    }

As you can see: only 4 questions are modified, that number coincides with the number of exams so that's why my guess tells me that the JOIN is producing some weird behaviour. Furthermore finished exams are 1 and 4, and that value to 1 coincides with the finished exams.

After a day trying to solve this, I just can think I'm doing something wrong or there's a bug after it.

image

agrosner commented 7 years ago

it looks like theres a pattern with the JOIN as you said. I would check the query result of the join you are using like the object QuestionsExam and see what the list of objects returned contains for fields. it might be something in the JOIN, and you might need to make a @QueryModel if the columns returned from the JOIN do not line up. It might be mapping only some of the columns because its mapping wrong table to wrong object.