如何用单个Flutter模型同时适配Isar数据库与JsonSerializable?
解决Isar与JsonSerializable关联类型冲突的单变量方案
你遇到的双变量冗余问题确实影响代码整洁度,其实可以通过自定义Json转换器实现单个变量同时适配Isar和JsonSerializable,无需维护两套字段。
核心思路
自定义JsonConverter,让JsonSerializable直接处理IsarLink<T>类型:
- 序列化(toJson):提取
IsarLink的value转为JSON对象 - 反序列化(fromJson):将JSON对象转为目标类型,赋值给
IsarLink的value
具体实现
1. 编写通用IsarLink转换器
import 'package:isar/isar.dart'; import 'package:json_annotation/json_annotation.dart'; class IsarLinkConverter<T> implements JsonConverter<IsarLink<T>, dynamic> { const IsarLinkConverter(); @override IsarLink<T> fromJson(dynamic json) { final link = IsarLink<T>(); if (json != null) { // 关联类需实现fromJson工厂方法 link.value = json is T ? json : _parseFromJson<T>(json); } return link; } @override dynamic toJson(IsarLink<T> link) => link.value?.toJson(); // 适配不同关联类的fromJson调用,可按需扩展类型判断 T _parseFromJson<T>(Map<String, dynamic> json) { switch (T.toString()) { case 'Organization': return Organization.fromJson(json) as T; case 'Domain': return Domain.fromJson(json) as T; case 'UserGroupPermissions': return UserGroupPermissions.fromJson(json) as T; default: throw UnsupportedError('未支持的类型: $T'); } } }
2. 改造UserGroup模型
移除冗余的普通类型字段,直接用IsarLink并绑定转换器注解:
@Collection() @JsonSerializable() class UserGroup { @JsonKey(ignore: true) Id localId = Isar.autoIncrement; @JsonKey(name: "_id") String? id; String name; String description; @JsonKey(converter: IsarLinkConverter<Domain>()) final IsarLink<Domain> domain = IsarLink<Domain>(); @JsonKey(converter: IsarLinkConverter<UserGroupPermissions>()) final IsarLink<UserGroupPermissions> permissions = IsarLink<UserGroupPermissions>(); @JsonKey(converter: IsarLinkConverter<Organization>()) final IsarLink<Organization> organization = IsarLink<Organization>(); UserGroup({ this.id, required this.name, required this.description, Domain? domain, UserGroupPermissions? permissions, Organization? organization, }) { // 构造函数中初始化IsarLink的初始值 if (domain != null) this.domain.value = domain; if (permissions != null) this.permissions.value = permissions; if (organization != null) this.organization.value = organization; } factory UserGroup.fromJson(Map<String, dynamic> json) => _$UserGroupFromJson(json); Map<String, dynamic> toJson() => _$UserGroupToJson(this); }
注意事项
- 所有关联类(如
Organization、Domain)必须实现fromJson和toJson方法 - 若项目中关联类较多,可通过反射简化转换器的类型判断(需添加
reflectable依赖并配置) - IsarLink必须在类中初始化(如
final+默认值或late修饰),否则Isar会抛出初始化错误
内容的提问来源于stack exchange,提问作者Jishnu Raj
相关产品推荐
相关产品推荐

