Flutter Isar数据库嵌套类存储异常:仅ProductGroup保存成功
Isar数据库仅保存ProductGroup数据,关联子对象未存储问题解决
问题描述
我定义了4个关联的数据类:ProductGroup、ProductVariant、ProductSize和ProductColor,通过IsarLinks建立嵌套关联关系。在将JSON数据解析后保存到Isar数据库的过程中,仅ProductGroup类的数据成功存储,ProductVariant、ProductSize和ProductColor的数据均未被保存。
相关代码
product_group.dart
@Collection() class ProductGroup { late Id id; @Index(caseSensitive: false) late String productGroupName; final productVariants = IsarLinks<ProductVariant>(); ProductGroup(); ProductGroup.fromJson(Map<String, dynamic> json) { id = json['Id']; productGroupName = json['PG']; if (json['Ps'] != null) { json['Ps'].forEach((variant) { productVariants.add(ProductVariant.fromJson(variant)); }); } } Map<String, dynamic> toJson() { final Map<String, dynamic> data = <String, dynamic>{}; data['Id'] = id; data['PG'] = productGroupName; data['Ps'] = productVariants.map((variant) => variant.toJson()).toList(); return data; } }
product_variant.dart
@Collection() class ProductVariant { late Id id; late String variantName; final productSizes = IsarLinks<ProductSize>(); ProductVariant(); ProductVariant.fromJson(Map<String, dynamic> json) { id = json['Id']; variantName = json['St']; if (json['Ss'] != null) { json['Ss'].forEach((v) { productSizes.add(ProductSize.fromJson(v)); }); } } Map<String, dynamic> toJson() { final Map<String, dynamic> data = <String, dynamic>{}; data['Id'] = id; data['St'] = variantName; data['Ss'] = productSizes.map((v) => v.toJson()).toList(); return data; } }
product_size.dart
@Collection() class ProductSize { late Id id; late String size; final productColors = IsarLinks<ProductColor>(); ProductSize(); ProductSize.fromJson(Map<String, dynamic> json) { id = json['Id']; size = json['S']; if (json['Cs'] != null) { json['Cs'].forEach((v) { productColors.add(ProductColor.fromJson(v)); }); } } Map<String, dynamic> toJson() { final Map<String, dynamic> data = <String, dynamic>{}; data['Id'] = id; data['S'] = size; data['Cs'] = productColors.map((color) => color.toJson()).toList(); return data; } }
product_color.dart
@Collection() class ProductColor { late Id id; late String colorName; late String colorHexCode; ProductColor(); ProductColor.fromJson(Map<String, dynamic> json) { id = json['Id']; colorName = json['C']; colorHexCode = json['CC']; } Map<String, dynamic> toJson() { final Map<String, dynamic> data = <String, dynamic>{}; data['Id'] = id; data['C'] = colorName; data['CC'] = colorHexCode; return data; } }
JSON解析与保存代码
convertJsonToIsar() async { try { // 测试用,从assets加载JSON,生产环境从服务器获取 final String response = await rootBundle.loadString('assets/pr_dump.json'); final data = await json.decode(response); List<ProductGroup> productGroupList = []; data.forEach((item) { productGroupList.add(ProductGroup.fromJson(item)); }); Isar _isar = getIsar(); _isar.writeTxnSync(() { _isar.productGroups.putAllSync(productGroupList, saveLinks: true); }); } catch (e) { // 错误处理 print('捕获到错误'); print(e.toString()); return 0; } }
解决方案
问题根源
Isar的IsarLinks关联依赖于子对象已存在于数据库中,saveLinks: true仅负责保存当前对象与已入库子对象的关联关系,不会自动递归保存未入库的嵌套子对象。原代码只保存了ProductGroup,未手动保存其下的ProductVariant、ProductSize和ProductColor,导致这些子对象无法被持久化。
修复步骤
递归逐层保存所有嵌套对象
在写入事务中,从最底层的ProductColor开始,逐层向上保存到ProductGroup,确保每个层级的对象都先入库,再建立关联:修改后的保存代码:
convertJsonToIsar() async { try { final String response = await rootBundle.loadString('assets/pr_dump.json'); final data = await json.decode(response); List<ProductGroup> productGroupList = []; data.forEach((item) { productGroupList.add(ProductGroup.fromJson(item)); }); Isar _isar = await getIsar(); await _isar.writeTxn(() async { // 先保存最底层的ProductColor for (var group in productGroupList) { for (var variant in group.productVariants) { for (var size in variant.productSizes) { await _isar.productColors.putAll(size.productColors); } // 保存ProductSize await _isar.productSizes.putAll(variant.productSizes); } // 保存ProductVariant await _isar.productVariants.putAll(group.productVariants); } // 最后保存ProductGroup,自动建立关联 await _isar.productGroups.putAll(productGroupList, saveLinks: true); }); } catch (e) { print('捕获到错误'); print(e.toString()); return 0; } }确保Isar实例注册所有集合
检查Isar初始化代码,确认4个集合都已注册,否则数据库无法识别这些对象类型:import 'package:isar/isar.dart'; import 'package:path_provider/path_provider.dart'; Future<Isar> getIsar() async { if (Isar.instanceNames.isEmpty) { final dir = await getApplicationDocumentsDirectory(); return await Isar.open( [ProductGroupSchema, ProductVariantSchema, ProductSizeSchema, ProductColorSchema], directory: dir.path, ); } return Isar.getInstance()!; }验证ID的有效性
- 确保JSON中的
Id是唯一非0整数,Isar默认自增ID为0时会自动生成新ID,若手动设置ID需避免重复。 - 如果不需要保留JSON中的ID,可去掉构造函数中
id = json['Id']的赋值,让Isar自动生成唯一ID,避免冲突。
- 确保JSON中的
关键说明
Isar的关联是基于对象ID的引用关系,只有子对象已存在于数据库中,父对象的IsarLinks才能正确保存关联。因此必须按照从底层到顶层的顺序,先保存所有子对象,再保存父对象并建立关联。
内容的提问来源于stack exchange,提问作者Haaris Ahamed
相关产品推荐
相关产品推荐

