如何组合两个流,其中第二个取决于第一个?

问题描述

我正在构建一个应用,其中 Document一个属于 DocumentTemplateDocumentFamily

我正在研究应用程序的基本 CRUD 操作,我需要一个 watchDocumentTemplateById 方法获取 DocumentTemplate 的流,但我还需要观察它的 DocumentFamily

问题是我不知道如何嵌套两个流,以便当 DocumentFamily 更新时,DocumentTemplate 将具有更新的 DocumentFamily

如果有人能告诉我正确的方法,我将不胜感激。 我使用 Flutter 和 ObjectBox 作为我的本地数据库

这是我开始实施的方法watchDocumentTemplateById(未完成):

@override
Stream<Either<DocumentTemplateFailure,DocumentTemplate>>
      watchDocumentTemplateById(UniqueId templateId) {
    return _Box
        .query(DocumentTemplateEntity_.id.equals(templateId.getorCrash()))
        .watch(triggerImmediately: true)
        .map((query) {
      final templateEntity = query.findFirst();

      if (null != templateEntity) {
        final familyOrFailureStream =
            _documentFamilyRepository.watchDocumentFamilyById(
                UniqueId.fromUniqueString(templateEntity.familyId));

        familyOrFailureStream.listen((familyOrFailure) {
          return familyOrFailure.fold(
            (failure) =>
                DocumentTemplateFailure.familyFailure(familyFailure: failure),(family) => templateEntity.todomain(family: family),);
        });
      }
      return left(const DocumentTemplateFailure.notFound());
    });
  }

以及上面提到的类(DocumentTemplate、DocumentTemplateEntity、DocumentFamily 和 DocumentFamilyEntity):

文档模板:

@freezed
class DocumentTemplate with _$DocumentTemplate {
  factory DocumentTemplate({
    required UniqueId id,required DocumentTemplateTitle title,required double leftMargin,required double topMargin,required double rightMargin,required double bottomMargin,required DocumentFamily family,}) = _DocumentTemplate;
}

文档模板实体:

@Entity()
class DocumentTemplateEntity {
  @Id()
  int obid = 0;

  @Unique()
  String id;
  String title;
  double leftMargin;
  double topMargin;
  double rightMargin;
  double bottomMargin;
  String familyId;

  DocumentTemplateEntity({
    required this.id,required this.title,required this.leftMargin,required this.topMargin,required this.rightMargin,required this.bottomMargin,required this.familyId,});

  DocumentTemplate todomain({
    required DocumentFamily family,}) =>
      DocumentTemplate(
        id: UniqueId.fromUniqueString(id),title: DocumentTemplateTitle(title),leftMargin: leftMargin,topMargin: topMargin,rightMargin: rightMargin,bottomMargin: bottomMargin,family: family,);

  factory DocumentTemplateEntity.fromDomain(DocumentTemplate template) =>
      DocumentTemplateEntity(
        id: template.id.getorCrash(),title: template.title.getorCrash(),leftMargin: template.leftMargin,topMargin: template.topMargin,rightMargin: template.rightMargin,bottomMargin: template.bottomMargin,familyId: template.family.id.getorCrash(),);
}

文档系列:

@freezed
class DocumentFamily with _$DocumentFamily {
  factory DocumentFamily({
    required UniqueId id,required int position,required String name,}) = _DocumentFamily;
}

文档家族实体:

@Entity()
class DocumentFamilyEntity {
  @Id()
  int obid = 0;

  @Unique()
  String id;
  String name;
  int position;

  DocumentFamilyEntity({
    required this.id,required this.name,required this.position,});

  DocumentFamily todomain() => DocumentFamily(
        id: UniqueId.fromUniqueString(id),name: name,position: position,);

  factory DocumentFamilyEntity.fromDomain(DocumentFamily family) =>
      DocumentFamilyEntity(
        id: family.id.getorCrash(),name: family.name,position: family.position,);
}

提前致谢!

编辑:

我尝试自己解决它并找到了 switchMap 方法,该方法似乎将两个流合二为一,但我不完全确定它是否适用于更新的 watchDocumentTemplateById 方法

参考:How do I nest Streams in Dart (map Streams to Stream events)?

  @override
  Stream<Either<DocumentTemplateFailure,DocumentTemplate>>
      watchDocumentTemplateById(UniqueId templateId) {
    return _Box
        .query(DocumentTemplateEntity_.id.equals(templateId.getorCrash()))
        .watch(triggerImmediately: true)
        .switchMap((query) {
      final templateEntity = query.findFirst();
      // if(null == templateEntity) return ??? DocumentTemplateFailure.notFound();
      final familyId = UniqueId.fromUniqueString(templateEntity!.familyId);

      return _documentFamilyRepository.watchDocumentFamilyById(familyId).map(
            (failureOrFamily) => failureOrFamily.fold(
              (failure) => left(
                DocumentTemplateFailure.familyFailure(familyFailure: failure),),(family) => right(
                templateEntity.todomain(family: family),);
    });
  }

解决方法

您是否考虑过直接在 DocumentFamilyDocumentTemplate 类上使用 @Entity?参见 this example 显示它与包 freezed

在任何情况下,您可能都需要将实体之间的链接表示为 ObjectBox relation 而不仅仅是一个普通的 ID 字段。

然后 box.query().link() 创建跨实体的查询。如果你 watch() 那个,它会在基础实体以及所有链接的实体发生变化时触发。