Flutter中如何通过Sqflite获取关联数据并转为JSON对象
在Flutter中用Sqflite关联查询任务与子任务并转为JSON
要实现将任务及其关联子任务以嵌套JSON格式返回,Sqflite本身不支持直接返回嵌套结构,需要自己处理数据关联逻辑,以下是两种可行的实现方式:
方式一:分步查询(先查任务,再批量查子任务)
这种方式逻辑简单直观,适合数据量不大的场景:
- 先查询所有任务数据
- 提取所有任务ID,批量查询对应的子任务
- 将子任务按
task_id分组,再映射到对应的任务中 - 将组装好的数据转为JSON
代码示例
import 'package:sqflite/sqflite.dart'; import 'dart:convert'; // 假设已初始化数据库,db为Database实例 Future<String> getAllTasksWithSubtasks() async { // 1. 查询所有任务 final List<Map<String, dynamic>> tasks = await db.query('task_table'); if (tasks.isEmpty) { return json.encode([]); } // 2. 提取所有任务ID,批量查询子任务 final List<int> taskIds = tasks.map((task) => task['id'] as int).toList(); final List<Map<String, dynamic>> subtasks = await db.query( 'subtask_table', where: 'task_id IN (${taskIds.map((id) => '?').join(',')})', whereArgs: taskIds, ); // 3. 将子任务按task_id分组 final Map<int, List<Map<String, dynamic>>> subtaskMap = {}; for (var subtask in subtasks) { final taskId = subtask['task_id'] as int; if (!subtaskMap.containsKey(taskId)) { subtaskMap[taskId] = []; } // 移除task_id字段,子任务中无需展示该关联字段 subtask.remove('task_id'); subtaskMap[taskId]!.add(subtask); } // 4. 组装任务与子任务的嵌套结构 final List<Map<String, dynamic>> result = []; for (var task in tasks) { final taskId = task['id'] as int; result.add({ ...task, 'subtasks': subtaskMap[taskId] ?? [], }); } // 转为JSON字符串 return json.encode(result); }
方式二:单表JOIN查询后内存组装
通过一次JOIN查询获取所有关联数据,再在内存中整理成嵌套结构,适合需要减少数据库查询次数的场景:
代码示例
import 'package:sqflite/sqflite.dart'; import 'dart:convert'; // 假设已初始化数据库,db为Database实例 Future<String> getAllTasksWithSubtasks() async { // 用LEFT JOIN关联任务和子任务,确保没有子任务的任务也能被返回 final List<Map<String, dynamic>> joinedData = await db.rawQuery(''' SELECT t.id AS task_id, t.name AS task_name, s.id AS subtask_id, s.name AS subtask_name FROM task_table t LEFT JOIN subtask_table s ON t.id = s.task_id '''); if (joinedData.isEmpty) { return json.encode([]); } // 组装嵌套结构 final Map<int, Map<String, dynamic>> taskMap = {}; for (var row in joinedData) { final taskId = row['task_id'] as int; // 如果任务未在map中,先初始化 if (!taskMap.containsKey(taskId)) { taskMap[taskId] = { 'id': taskId, 'name': row['task_name'], 'subtasks': [], }; } // 如果子任务存在(LEFT JOIN可能返回null),添加到对应任务的子任务列表 if (row['subtask_id'] != null) { taskMap[taskId]!['subtasks'].add({ 'id': row['subtask_id'], 'name': row['subtask_name'], }); } } // 转为列表并转JSON final List<Map<String, dynamic>> result = taskMap.values.toList(); return json.encode(result); }
注意事项
- 若不需要保留
task_id字段在子任务中,记得在组装时移除(如方式一所示) - 使用
json.encode()时,确保所有数据类型都是JSON支持的类型(如int、String、List、Map等) - 数据量较大时,方式二的JOIN查询能减少数据库IO次数,效率更高
内容的提问来源于stack exchange,提问作者draxex
相关产品推荐
相关产品推荐

