【问题标题】:Two queries where the second is depended to the first one两个查询,其中第二个依赖于第一个
【发布时间】:2012-11-14 22:10:30
【问题描述】:

我正在尝试在 Phonegap (Cordova) 应用程序中显示项目列表,其中每个项目都需要额外的查询。

为了简单起见,我将用一个例子来解释它。假设student 可以有多个courses,course 可以有很多students(多对多),我想显示一个列表,显示学生注册的课程。像这样:

  • 学生 1:课程 1、课程 2
  • 学生 2:课程 1、课程 3、课程 5
  • 学生 3:课程 2
  • ...

首先,我需要一个查询来遍历所有学生,然后对于每个学生,我需要查询数据库以了解学生注册了哪些课程:

db.transaction(function(tx) {
    tx.executeSql('SELECT `student`.`id`, `student`.`name` ' +
            'FROM `student`',
            [],
            function(tx, resultSet) {
                for(var i = 0; i < resultSet.rows.length; i++) {
                    tx.executeSql('SELECT `course`.`name` ' +
                            'FROM `student_has_course` ' +
                            'INNER JOIN `student` ON `student_has_course`.`student_id` = `student`.`id` ' +
                            'INNER JOIN `course` ON `student_has_course`.`course_id` = `course`.`id` ' +
                            'WHERE `student`.`id` = ?'
                            [resultSet.rows.item(i).id],
                            function(tx2, resultSet2) {
                                // TODO
                            });
                }
            });
}, function(err) {
    showError('Error getting students from the DB (' + err.message + ')');
}, function() {
    alert('success!');
});

现在,问题是在第二个回调函数(“TODO”所在的位置)中,我没有引用上一个查询的任何数据。例如,如果我尝试alert(i),它会警告 76,相当于resultSet.rows.length。这显然是因为这两个回调函数都是异步的。我怎样才能克服这个问题并打印如上所示的列表?

非常感谢任何帮助。

【问题讨论】:

    标签: javascript cordova asynchronous transactions


    【解决方案1】:

    您应该能够通过将属性附加到回调函数本身来解决这个问题,如下所示:

    cb = function cbfunc() {
         doStuffWith(cbfunc.data)
    }
    cb.data = ... // whatever
    tx.executeSQL(..., cb)
    

    不过,如果我可以通过使用单个查询产生预期结果来避免第二次回调,我会三思而后行。在这种情况下:

    select student.id, student.name, course.name from student
        inner join student_has_course on student.id = student_has_course.student_id
        inner join course on student_has_course.course_id = course.id
            order by student.id;
    

    在循环中,将 student.id 与上一次迭代中的比较,以了解何时打印换行符和新学生姓名,从而获得所需的输出格式。

    【讨论】:

    • 谢谢你,@jop。不过,这只是一种解决方法,我正在寻找一种适用于任何情况的通用解决方案
    • 我明白了。我对其进行了编辑以提供更通用的解决方案,即使对于这个特定示例,单个 SQL 仍然看起来更好。