Clean架构下使用Isar Generator遇参数与属性类型不匹配错误
我在项目中采用Clean架构,想给应用添加数据库,选择了Isar数据库。按照Clean架构要求,只在Model层而非Entity层创建Isar集合,但给Model创建集合并用Isar Generator生成代码时,一直报错。
错误信息
[INFO] Generating build script completed, took 875ms
[INFO] Reading cached asset graph completed, took 231ms
[INFO] Checking for updates since last build completed, took 3.3s
[SEVERE] isar_generator on lib/data/models/plugin.dart:Constructor parameter type does not match property type
package:meiyou/data/models/plugin.dart:24:11
╷
24 │ super.dependencies,
│ ^^^^^^^^^^^^
╵
[INFO] Running build completed, took 5.2s
[INFO] Caching finalized dependency graph completed, took 181ms
[SEVERE] Failed after 5.4s
相关代码
import 'dart:convert'; import 'package:meiyou/core/utils/extenstions/iterable.dart'; import 'package:meiyou/core/utils/from_entity.dart'; import 'package:meiyou/domain/entities/plugin.dart'; import 'package:isar/isar.dart'; part 'plugin.g.dart'; @collection class Plugin extends PluginEntity { final Id id; @override List<Dependency>? get dependencies => super.dependencies?.mapAsList<Dependency>( (it) => it is Dependency ? it : Dependency.fromEntity(it)); const Plugin({ this.id = Isar.autoIncrement, required super.name, required super.source, required super.version, super.icon, super.info, super.dependencies, }); factory Plugin.fromEntity(PluginEntity entity) { return createFromEntity<PluginEntity, Plugin>( entity, Plugin( name: entity.name, source: entity.source, version: entity.version, icon: entity.icon, info: entity.info, dependencies: entity.dependencies?.mapAsList<Dependency>( (it) => it is Dependency ? it : Dependency.fromEntity(it)), )); } factory Plugin.decode(String jsonString) => Plugin.fromJson(jsonDecode(jsonString)); factory Plugin.fromJson(dynamic json) { return Plugin( name: json['name'], source: json['source'], version: json['version'], icon: json['icon'], info: json['info'], dependencies: (json['dependencies'] as List?) ?.mapAsList((it) => Dependency.fromJson(it)), ); } String get encode => jsonEncode(toJson()); Map<String, dynamic> toJson() { return { "name": name, "source": source, "version": version, "icon": icon, "info": info, "dependencies": dependencies?.mapAsList((e) => e.toJson()), }; } Plugin copyWith({ String? name, String? source, String? version, String? icon, String? info, List<Dependency>? dependencies, }) { return Plugin( name: name ?? this.name, source: source ?? this.source, version: version ?? this.version, icon: icon ?? this.icon, info: info ?? this.info, dependencies: dependencies ?? this.dependencies, ); } @override String toString() { return '''Plugin(name: $name, source: $source, version: $version, icon: $icon, info: $info, dependencies: $dependencies)'''; } } @embedded class Dependency extends DependencyEntity { final Id id; const Dependency({ this.id = Isar.autoIncrement, required super.name, required super.source, required super.version, }); factory Dependency.fromEntity(DependencyEntity entity) { return Dependency( name: entity.name, source: entity.source, version: entity.version, ); } factory Dependency.decode(String jsonString) => Dependency.fromJson(jsonDecode(jsonString)); factory Dependency.fromJson(dynamic json) { return Dependency( name: json['name'], source: json['source'], version: json['version'], ); } String get encode => jsonEncode(toJson()); Map<String, dynamic> toJson() { return { 'name': name, 'source': source, 'version': version, }; } @override String toString() { return '''Dependency(name: $name, source: $source, version: $version)'''; } }
问题原因
报错核心是:你在Plugin类中重写了dependencies属性,将父类PluginEntity的List<DependencyEntity>?类型转换成了List<Dependency>?类型,但构造函数直接传递super.dependencies时,Isar Generator无法识别这种类型不匹配——它要求构造参数类型和类中属性类型完全一致。
解决办法
方案一:重新定义Model层的dependencies属性
去掉@override,自己定义Isar可识别的dependencies属性,同时在构造函数中处理父类的依赖赋值:
@collection class Plugin extends PluginEntity { final Id id; final List<Dependency>? dependencies; const Plugin({ this.id = Isar.autoIncrement, required super.name, required super.source, required super.version, super.icon, super.info, List<Dependency>? dependencies, }) : dependencies = dependencies, super(dependencies: dependencies?.map((d) => d as DependencyEntity).toList()); // 其他代码保持不变 }
方案二:给重写的属性添加@ignore注解
如果坚持重写父类属性,可通过@ignore让Isar忽略该属性,同时定义一个Isar可存储的属性:
@collection class Plugin extends PluginEntity { final Id id; @ignore @override List<Dependency>? get dependencies => super.dependencies?.mapAsList<Dependency>( (it) => it is Dependency ? it : Dependency.fromEntity(it)); final List<Dependency>? _storedDependencies; const Plugin({ this.id = Isar.autoIncrement, required super.name, required super.source, required super.version, super.icon, super.info, List<Dependency>? dependencies, }) : _storedDependencies = dependencies, super(dependencies: dependencies?.map((d) => d as DependencyEntity).toList()); // 其他代码保持不变 }
额外说明
Clean架构下Model层继承Entity层是合理的,但Isar对实体类类型要求严格,所有需存储的属性必须是Isar支持的类型,且构造参数与属性类型要完全匹配。优先推荐方案一,既符合Clean架构分层要求,又能满足Isar生成规则。
内容的提问来源于stack exchange,提问作者Omega500

