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

如何在Flutter中正确存储Supabase双表查询结果至数据模型?

Flutter中正确转换Supabase多表查询结果为对象的解决方案

问题场景

使用Supabase查询questions表及其关联的categories表(主分类和子分类),API返回的response包含正确数据,但转换为自定义Question对象时失败,导致页面持续显示CircularProgressIndicator,调试时打印questions无输出。

核心问题

sub_category_id允许为null,对应的sub_category字段在返回结果中可能是null,直接通过json['sub_category']['category_name']访问会触发空指针异常,中断对象转换流程;另外fromJson方法的参数类型不够严谨,增加了潜在的类型风险。

解决步骤

  • 修复空安全处理:对可能为null的关联字段使用?.安全访问符,配合??空合并运算符设置默认值(或保留null),避免空指针。
  • 严谨类型声明:将fromJson的参数类型从Map<dynamic, dynamic>改为Map<String, dynamic>,符合Supabase返回数据的实际类型。
  • 添加调试辅助方法:给Question类添加toString()方法,方便调试时打印对象内容。
  • 细化异常捕获:在对象转换环节单独捕获异常,定位具体出错的条目,避免整个请求失败。

修改后的代码示例

优化后的Question类

class Question {
  final int id;
  final String questionText;
  final String? questionId;
  final int mainCategoryId;
  final String mainCategoryName;
  final int? subCategoryId;
  final String? subCategoryName;

  Question({
    required this.id,
    required this.questionText,
    this.questionId,
    required this.mainCategoryId,
    required this.mainCategoryName,
    this.subCategoryId,
    this.subCategoryName,
  });

  // 优化后的fromJson方法,处理空安全和严谨类型
  Question.fromJson(Map<String, dynamic> json)
      : id = json['id'] as int,
        questionText = json['question_text'] as String,
        questionId = json['question_id'] as String?,
        mainCategoryId = json['main_category_id'] as int,
        // 主分类不会为null,直接安全访问
        mainCategoryName = (json['main_category'] as Map<String, dynamic>)['category_name'] as String,
        subCategoryId = json['sub_category_id'] as int?,
        // 子分类可能为null,使用判空处理
        subCategoryName = json['sub_category'] != null 
            ? (json['sub_category'] as Map<String, dynamic>)['category_name'] as String?
            : null;

  // 添加toString方便调试
  @override
  String toString() {
    return 'Question(id: $id, questionText: $questionText, mainCategoryName: $mainCategoryName, subCategoryName: $subCategoryName)';
  }
}

优化后的QuestionRepository类

class QuestionRepository {
  final supabase = Supabase.instance.client;

  Future<List<Question>> getQuestions() async {
    try {
      final response = await supabase.from('questions').select(
        '*, main_category: main_category_id(*), sub_category: sub_category_id(*)',
      );

      if (response.isNotEmpty) {
        final List<Question> questions = [];
        for (final data in response) {
          try {
            // 单独捕获每个条目转换的异常,方便定位问题
            questions.add(Question.fromJson(data as Map<String, dynamic>));
          } catch (e) {
            print('转换条目失败: $data, 错误: $e');
          }
        }
        // 打印转换后的结果,验证是否成功
        print(questions);
        return questions;
      } else {
        throw Exception('没有查询到问题数据');
      }
    } catch (error) {
      throw Exception('获取问题失败: $error');
    }
  }
}

验证方法

  1. 运行代码后查看控制台打印的questions列表,确认对象是否正确转换
  2. 若有转换失败的条目,控制台会输出具体的错误信息和对应的数据,便于针对性修复

内容的提问来源于stack exchange,提问作者Sheenergizer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 03:38:11