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

Flutter中ObjectBox关联模型赋值及Json序列化问题排查

问题

将Json转Dart工具生成的模型类作为ObjectBox的@Entity实体类使用时,遇到以下问题:

  1. 无法正确配置与Area、ShipmentAction的关联关系;
  2. 配置关联后,fromJson和toJson方法失效;
  3. 批量存储ShipmentDetail时,循环内对象的Area属性正常,但存储后查询列表中Area信息丢失。

核心需求:在ShipmentDetail类中正确配置与Area、ShipmentAction的关联,同时保证fromJson/toJson方法正常运行。

问题分析
  1. 关联配置错误:

    • ShipmentDetail中objshipmentActions声明错误,应为ToMany<ShipmentAction>()而非ToMany<ShipmentAction>;
    • @Backlink参数错误,需指向ShipmentAction中关联ShipmentDetail的字段名shipmentDetails,而非实体类名;
    • 冗余字段:同时存在普通List类型的shipmentActions和ObjectBox的ToMany类型字段,导致序列化逻辑混乱。
  2. 序列化方法问题:

    • fromJson未正确处理ShipmentAction的关联,应将解析后的对象添加到ObjectBox的ToMany字段,而非冗余List;
    • toJson需基于ObjectBox的关联字段生成JSON,而非废弃的冗余字段。
  3. 批量存储问题:

    • 存储ShipmentDetail前未先持久化关联的Area实体,ObjectBox无法自动关联未存储的对象;
    • 属性拷贝不完整,未正确处理关联关系的持久化逻辑。
修正后的完整实体类代码

ShipmentDetail 实体类

import 'package:objectbox/objectbox.dart';
import 'area.dart';
import 'shipment_action.dart';
import 'shipment_type.dart';

@Entity()
class ShipmentDetail {
  @Id()
  int id = 0;
  late String barcode;
  late ShipmentType? shipmentType;
  late bool isSynced = false;
  late String startDeliveryTime = "00:00:00";
  late String endDeliveryTime = "00:00:00";
  late bool isChange = false;
  late String civilId;
  late String? latitude;
  late String? longitude;

  // 与Area的一对一关联
  final area = ToOne<Area>();
  // 与ShipmentAction的一对多反向关联,指向ShipmentAction中的shipmentDetails字段
  @Backlink()
  final shipmentActions = ToMany<ShipmentAction>();

  ShipmentDetail({
    required this.barcode,
    this.shipmentType,
    this.isSynced = false,
    required this.civilId,
    this.latitude,
    this.longitude,
  });

  // 空构造函数用于ObjectBox内部实例化
  ShipmentDetail.empty();

  ShipmentDetail.fromJson(Map<String, dynamic> json) {
    barcode = json['barcode'];
    civilId = json['civilId'] ?? '';
    longitude = json['longitude'] ?? '';
    latitude = json['latitude'] ?? '';
    isSynced = json['isSynced'] ?? false;
    startDeliveryTime = json['startDeliveryTime'] ?? "00:00:00";
    endDeliveryTime = json['endDeliveryTime'] ?? "00:00:00";
    isChange = json['isChange'] ?? false;

    // 解析Area关联
    if (json['area'] != null) {
      area.target = Area.fromJson(json['area']);
    }

    // 解析ShipmentType
    if (json['shipmentType'] != null) {
      shipmentType = ShipmentType.fromJson(json['shipmentType']);
    }

    // 解析ShipmentAction列表并建立双向关联
    if (json['shipmentActions'] != null) {
      shipmentActions.clear();
      json['shipmentActions'].forEach((v) {
        final action = ShipmentAction.fromJson(v);
        action.shipmentDetails.target = this;
        shipmentActions.add(action);
      });
    }
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = {};
    data['barcode'] = barcode;
    data['civilId'] = civilId;
    data['longitude'] = longitude;
    data['latitude'] = latitude;
    data['isSynced'] = isSynced;
    data['startDeliveryTime'] = startDeliveryTime;
    data['endDeliveryTime'] = endDeliveryTime;
    data['isChange'] = isChange;

    // 序列化Area关联
    if (area.target != null) {
      data['area'] = area.target!.toJson();
    }

    // 序列化ShipmentType
    if (shipmentType != null) {
      data['shipmentType'] = shipmentType!.toJson();
    }

    // 序列化ShipmentAction列表
    if (shipmentActions.isNotEmpty) {
      data['shipmentActions'] = shipmentActions.map((v) => v.toJson()).toList();
    }

    return data;
  }
}

Area 实体类

import 'package:objectbox/objectbox.dart';

@Entity()
class Area {
  @Id()
  int id = 0; // ObjectBox要求Id为非空int,默认0表示未持久化
  late String? description;
  late String? descriptionEn;
  late int? paciId;

  Area({
    this.id = 0,
    required this.description,
    this.descriptionEn = "",
    required this.paciId,
  });

  Area.fromJson(Map<String, dynamic> json) {
    id = json['id'] ?? 0;
    description = json['description'] ?? '';
    descriptionEn = json['descriptionEn'] ?? "";
    paciId = json['paciId'] ?? 0;
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = {};
    data['id'] = id;
    data['description'] = description;
    data['descriptionEn'] = descriptionEn;
    data['paciId'] = paciId;
    return data;
  }
}

ShipmentAction 实体类

import 'package:objectbox/objectbox.dart';
import 'shipment_detail.dart';
import 'action_type.dart';

@Entity()
class ShipmentAction {
  @Id()
  int id = 0;
  late int? newBulkId;
  late String? description;
  late ActionType? actions;

  // 与ShipmentDetail的多对一关联
  final shipmentDetails = ToOne<ShipmentDetail>();

  ShipmentAction({
    this.id = 0,
    required this.newBulkId,
    required this.description,
    this.actions,
  });

  ShipmentAction.fromJson(Map<String, dynamic> json) {
    id = json['id'] ?? 0;
    newBulkId = json['newBulkId'];
    description = json['description'] ?? '';

    if (json['actions'] != null) {
      actions = ActionType.fromJson(json['actions']);
    }
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = {};
    data['id'] = id;
    data['newBulkId'] = newBulkId;
    data['description'] = description;

    if (actions != null) {
      data['actions'] = actions!.toJson();
    }

    return data;
  }
}
批量存储代码修正
import 'package:objectbox/objectbox.dart';
import 'shipment_detail.dart';
import 'area.dart';

class ShipmentDbService {
  late Box<ShipmentDetail> _storageShipment;
  late Box<Area> _areaBox;
  late Box<ShipmentAction> _actionBox;

  ShipmentDbService(Store store) {
    _storageShipment = store.box<ShipmentDetail>();
    _areaBox = store.box<Area>();
    _actionBox = store.box<ShipmentAction>();
  }

  Result<List<ShipmentDetail>> addAll(List<ShipmentDetail> data) {
    try {
      for (var item in data) {
        // 1. 先持久化关联的Area(未持久化时)
        if (item.area.target != null) {
          final area = item.area.target!;
          if (area.id == 0) {
            area.id = _areaBox.put(area);
          }
          item.area.target = area;
        }

        // 2. 持久化关联的ShipmentAction列表
        for (var action in item.shipmentActions) {
          if (action.id == 0) {
            action.id = _actionBox.put(action);
          }
        }

        // 3. 存储ShipmentDetail
        if (item.id == 0) {
          item.id = _storageShipment.put(item);
        } else {
          _storageShipment.put(item);
        }
      }

      final shipmentsLst = _storageShipment.getAll().toList();
      return Result.success(shipmentsLst);
    } catch (e) {
      return Result.error(e.toString());
    }
  }
}

// 自定义结果封装类
class Result<T> {
  final bool isSuccess;
  final T? data;
  final String? error;

  Result.success(this.data) : isSuccess = true, error = null;
  Result.error(this.error) : isSuccess = false, data = null;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 01:17:04