首页 > 解决方案 > 如何在 Firebase(Flutter/dart)中添加具有 DocumentReference 类型的对象?

问题描述

我想在 firebase 的帖子文档中引用一个类别文档。这是我的数据类,我也在使用 freezed 和 json_serializer:

    部分“post_dto.freezed.dart”;
    部分'post_dto.g.dart';
    部分'category_dto.freezed.dart';
    部分'category_dto.g.dart';
    
    @冻结
    带有 _$PostDTO { 的抽象类 PostDTO
      常量 PostDTO._();
    
      常量工厂 PostDTO({
        @JsonKey(忽略:真)字符串?ID,
        必需的字符串标题,
        必需的字符串描述,
        @DocumentReferenceConveter() 文档参考?类别参考,
      }) = _PostDTO;
    
      工厂 PostDTO.fromJson(Map json) =>
          _$PostDTOFromJson(json);
    
      工厂 PostDTO.fromFireStore(DocumentSnapshot 文档) {
        地图数据 = document.data() as Map;
        return PostDTO.fromJson(data).copyWith(id: document.id);
      }
    }
    
    @冻结
    抽象类 CategoryDTO 与 _$CategoryDTO {
      常量类别DTO._();
    
      常量工厂 CategoryDTO({
        必需的字符串图标,
        必需的字符串名称,
      }) = _CategoryDTO;
    
     工厂 CategoryDTO.fromFireStore(DocumentSnapshot 文档) {
        地图数据 = document.data() as Map;
        返回 CategoryDTO.fromJson(data);
      }
    
      工厂 CategoryDTO.fromJson(Map json) =>
          _$CategoryDTOFromJson(json);
    }

当我运行 build_runner 时,我得到了这个错误:

    [严重] json_serializable:lib/infrastructure/post/post_dto.dart 上的 json_serializable:
    
    无法为“categoryReference”生成“fromJson”代码。
    要支持“DocumentReference”类型,您可以:
    * 使用`JsonConverter`
      https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonConverter-class.html
    * 使用 `JsonKey` 字段 `fromJson` 和 `toJson`
      https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonKey/fromJson.html
      https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonKey/toJson.html
    包:UPLFY/infrastructure/post/post_dto.freezed.dart:373:41
        ╷
    373│最终的DocumentReference?类别参考;
        │ ^^^^^^^^^^^^^^^^^
        ╵
    [INFO] 运行构建完成,耗时 2.5 秒
    
    [INFO] 正在缓存最终的依赖关系图...
    [INFO] 缓存最终依赖图完​​成,耗时 44 毫秒
    
    [严重] 2.5 秒后失败

所以尝试使用 JsonConverter 但我不确定如何将 json 对象转换为 DocumentReference ...

    类 DocumentReferenceConveter
        实现 JsonConverter,对象> {
      常量 DocumentReferenceConveter();
    
      @覆盖
      DocumentReference fromJson(Object json) {
        return //TODO: 将 json 转换为 DocumentReference
      }
    
      @覆盖
      对象 toJson(DocumentReference documentReference) =>
          文件参考;
    }

标签: jsonfirebaseflutterdartgoogle-cloud-firestore

解决方案


我能够从我在网上找到的研究中总结出我的解决方案,并且到目前为止想出了这个。

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:json_annotation/json_annotation.dart';

class DocumentReferenceJsonConverter
    implements JsonConverter<DocumentReference?, Object?> {
  const DocumentReferenceJsonConverter();

  @override
  DocumentReference? fromJson(Object? json) {
    return tryCast<DocumentReference>(json);
  }

  @override
  Object? toJson(DocumentReference? documentReference) => documentReference;
}
T? tryCast<T>(value) {
  return value == null ? null : value as T;
}
...
import 'package:freezed_annotation/freezed_annotation.dart';

part 'user_profile.freezed.dart';
part 'user_profile.g.dart';

@freezed
class UserProfile with _$UserProfile {
  const UserProfile._();

  @TimestampConverter()
  @DocumentReferenceJsonConverter()
  @JsonSerializable(
    explicitToJson: true,
    fieldRename: FieldRename.snake,
    includeIfNull: false,
  )
  factory UserProfile({
    @JsonKey(ignore: true) DocumentReference? reference,
    String? avatarUrl,
    required String email,
    required String firstName,
    required String lastName,
    Gender? gender,
    DateTime? birthday,
    String? additionalInfo,
    Contact? contact,
    DocumentReference? familyReference,
    DateTime? createdAt,
  }) = _UserProfile;

  factory UserProfile.empty() => UserProfile(email: '', firstName: '', lastName: '');

  factory UserProfile.fromJson(Map<String, dynamic> json) => _$UserProfileFromJson(json);

  factory UserProfile.fromDocument(DocumentSnapshot documentSnapshot) {
    final data = documentSnapshot.data();
    return data != null
        ? UserProfile.fromJson(data as Map<String, dynamic>)
            .copyWith(reference: documentSnapshot.reference)
        : UserProfile.empty();
  }

推荐阅读