You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中如何通过Sqflite获取关联数据并转为JSON对象

在Flutter中用Sqflite关联查询任务与子任务并转为JSON

要实现将任务及其关联子任务以嵌套JSON格式返回,Sqflite本身不支持直接返回嵌套结构,需要自己处理数据关联逻辑,以下是两种可行的实现方式:

方式一:分步查询(先查任务,再批量查子任务)

这种方式逻辑简单直观,适合数据量不大的场景:

  1. 先查询所有任务数据
  2. 提取所有任务ID,批量查询对应的子任务
  3. 将子任务按task_id分组,再映射到对应的任务中
  4. 将组装好的数据转为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 22:52:50