flutter firestore 事务在写入之前读取错误

flutter firestore transaction reads before writes give error

这是我正在尝试的代码 运行:

class TransactionEntity {
  final Entity entity;
  final DocumentReference<Map<String, dynamic>> document;
  DocumentSnapshot? snapshot;
  final String writeOperation;

  TransactionEntity(
      {required this.entity,
      required this.document,
      required this.writeOperation,
      this.snapshot});

  void set(DocumentSnapshot documentSnapshot) {
    snapshot = documentSnapshot;
  }

  DocumentSnapshot? get documentSnapshot {
    return snapshot;
  }

  Transaction? executeWriteOperation(Transaction transaction) {
    if (writeOperation == "update") {
      Map<String, dynamic> attributesToUpdate = {};
      var entityData = entity.toJson();
      if (snapshot != null) {
        var data = snapshot!.data() as Map<String, dynamic>;
        entityData.forEach((attributeName, attributeValue) {
          if (attributeValue is List) {
            if (!listEquals(attributeValue, data[attributeName])) {
              attributesToUpdate[attributeName] = data[attributeName];
            }
          } else if (attributeValue is Entity || attributeValue is Map) {
            var nestedMap = {};
            var nestedObject = attributeValue.toJson();
            nestedObject.forEach((key, value) {
              if (value != data[attributeName][key]) {
                String newKey = "$attributeName.$key";
                nestedMap[newKey] = data[attributeName][key];
              }
            });
            if (nestedMap.isNotEmpty) {
              attributesToUpdate[attributeName] = nestedMap;
            }
          } else if (data[attributeName] != attributeValue) {
            attributesToUpdate[attributeName] = attributeValue;
          }
        });
      }
      return transaction.update(document, attributesToUpdate);
    } else if (writeOperation == "set") {
      return transaction.set(document, entity.toJson());
    } else if (writeOperation == "delete" && snapshot!.exists) {
      return transaction.delete(document);
    }
    return null;
  }
}




  Future<void> updateProductTransaction(
    Product product,
    int nLocations,
  ) async {
    try {
      List<ProductVariant> productVariants =
          product.variants == null || product.variants!.isEmpty
              ? [product.defaultVariant!]
              : product.variants!;
      List<ProductOption> productOptions = product.options ?? [];
      DocumentReference<Map<String, dynamic>> productDocument =
          FirebaseFirestore.instance.collection("product").doc(product.id);
      List<DocumentReference<Map<String, dynamic>>> productVariantDocuments =
          await FirebaseFirestore.instance
              .collectionGroup("productVariant")
              .where("parentId", isEqualTo: product.id)
              .get()
              .then((value) => value.docs.map((e) => e.reference).toList());
      Map<String, List<DocumentReference<Map<String, dynamic>>?>>
          inventoryItemDocuments = {};

      for (var variant in productVariants) {
        await FirebaseFirestore.instance
            .collectionGroup("inventoryItem")
            .where("parentId", isEqualTo: variant.id)
            .get()
            .then((value) {
          inventoryItemDocuments[variant.id!] =
              value.docs.map((e) => e.reference).toList();
        });
        if (inventoryItemDocuments.isEmpty) {
          inventoryItemDocuments[variant.id!] =
              List.generate(nLocations, (index) => null);
        }
      }
      List<DocumentReference<Map<String, dynamic>>> productOptionDocuments = [];
      if (productOptions.isNotEmpty) {
        productOptionDocuments = await FirebaseFirestore.instance
            .collectionGroup("productOption")
            .where("parentId", isEqualTo: product.parentId)
            .get()
            .then((value) => value.docs.map((e) => e.reference).toList());
      }
      return await FirebaseFirestore.instance
          .runTransaction((transaction) async {
        DocumentSnapshot productSnapshot =
            await transaction.get(productDocument);
        if (!productSnapshot.exists) {
          throw EntityException("Prodotto non esistente!");
        }
        List<TransactionEntity> transactions = [];
        transactions.add(TransactionEntity(
          entity: product,
          document: productDocument,
          writeOperation: "update",
          snapshot: productSnapshot,
        ));
    for (var productVariant in productVariants) {
      DocumentSnapshot? productVariantSnapshot = await transaction.get(
          productVariantDocuments.firstWhere(
              (variant) => variant.id == productVariant.id,
              orElse: null));
      var productVariantDocument = FirebaseFirestore.instance.doc(
          "{product/${product.id}/productVariant/${productVariant.id}}");
      if (productVariantSnapshot.exists) {
        transactions.add(TransactionEntity(
          entity: productVariant,
          document: productVariantDocument,
          writeOperation: "update",
          snapshot: productVariantSnapshot,
        ));
        for (var inventoryItem in productVariant.inventoryItems!) {
          var inventoryItemDocument = FirebaseFirestore.instance.doc(
            "{product/${product.id}/productVariant/${productVariant.id}/inventoryItem/${inventoryItem.id}",
          );
          var doc = inventoryItemDocuments[productVariant.id]!.firstWhere(
              (item) => item?.id == inventoryItem.id,
              orElse: null);
          DocumentSnapshot? inventoryItemSnapshot;
          if (doc != null) await transaction.get(doc);
          transactions.add(TransactionEntity(
            entity: inventoryItem,
            document: inventoryItemDocument,
            writeOperation: "update",
            snapshot: inventoryItemSnapshot,
          ));
        }
      } else {
        transactions.add(TransactionEntity(
          entity: productVariant,
          document: productVariantDocument,
          writeOperation: "set",
        ));
        for (var inventoryItem in productVariant.inventoryItems!) {
          var inventoryItemDocument = FirebaseFirestore.instance.doc(
            "{product/${product.id}/productVariant/${productVariant.id}/inventoryItem/${inventoryItem.id}",
          );
          transactions.add(TransactionEntity(
            entity: inventoryItem,
            document: inventoryItemDocument,
            writeOperation: "set",
          ));
        }
      }
    }
    for (var optionDocument in productOptionDocuments) {
      DocumentSnapshot? productOptionSnapshot =
          await transaction.get(optionDocument);
      var option = productOptions
          .firstWhere((option) => option.id == optionDocument.id);
      var productOptionDocument = FirebaseFirestore.instance
          .doc("{product/${product.id}/productOption/${option.id}}");
      if (productOptionSnapshot.exists) {
        transactions.add(TransactionEntity(
          entity: option,
          document: productOptionDocument,
          writeOperation: "update",
          snapshot: productOptionSnapshot,
        ));
      } else {
        transactions.add(TransactionEntity(
            entity: option,
            document: productOptionDocument,
            writeOperation: "set"));
      }
    }
    } catch (e, stacktrace) {
      print(stacktrace);
      throw e;
    }
  }

当它 运行 我得到一个错误:

    dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 251:49  throw_
packages/firebase_core/src/internals.dart 91:18                               <fn>
dart-sdk/lib/async/zone.dart 1687:54                                          runUnary
dart-sdk/lib/async/future_impl.dart 178:22                                    handleError
dart-sdk/lib/async/future_impl.dart 779:46                                    handleError
dart-sdk/lib/async/future_impl.dart 800:13                                    _propagateToListeners
dart-sdk/lib/async/future_impl.dart 610:5                                     [_completeError]
dart-sdk/lib/async/future_impl.dart 879:16                                    <fn>
dart-sdk/lib/async/zone.dart 1692:54                                          runBinary
dart-sdk/lib/async/future_impl.dart 175:22                                    handleError
dart-sdk/lib/async/future_impl.dart 779:46                                    handleError

正如您在代码中看到的,所有读取操作都在写入操作之前执行。 我在 updateProductTransaction 方法中使用了一个 catch,但为什么没有捕获到那个异常? TransactionEntity 收集文档和操作以在读取后执行。 ProductVariant、ProductOptions 是 Product 集合的子集合。 InventoryItem 是 ProductVariant 子集合的子集合。

由于路径错误,找不到文档,例如:

  "{product/${product.id}/productVariant/${productVariant.id}}");

我不得不删除“{”、“}”。