首页 > 解决方案 > 在 Firestore 中使用 runTransaction 方法的同时写入操作不起作用

问题描述

我正在开发一个可以获取反馈的颤振应用程序。所以,我需要一次处理多个表单提交。我正在使用 firestore 中提供的 runTransaction 方法来处理它。但是,当我尝试从两台设备同时提交反馈表时,只会记录来自一台设备的响应。

文档中提到,如果任何客户端修改文档,runTransaction 方法会重试事务。但是,在我的情况下并没有发生这种情况。我该如何解决这个问题?

这是我编写的代码。

uploadFeedback(context) {
    ProgressDialog pr = new ProgressDialog(context);
    pr.style(message: 'Submitting response');
    pr.show();
    var ref = Firestore.instance.collection('/feedbacks').document(widget.data);
    Firestore.instance.runTransaction((transaction) async {
      // Read operation
      var doc = await ref.get();
      var prev = doc['scores'];
      attended = doc['attended'];
      attended.add(email);
      for (int i = 0; i < questionObjectList.length; i++) {
        int response = questionObjectList[i].response;
        prev[i.toString()][response - 1] += 1;
      }
      updated = prev;

      // Update operation
      return transaction.update(ref, {
        'scores': updated,
        'attended': attended
      });
    }).then((val) {
      pr.hide();
      Fluttertoast.showToast(msg: 'Feedback submitted successfully');
    }).catchError((e) {
      pr.hide();
      Fluttertoast.showToast(msg: 'Some error occured');
      throw Error();
    });
  }

还附上整个文件的代码

import 'package:awesome_dialog/awesome_dialog.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:feedback_system/public/Metrics/effort_rating.dart';
import 'package:feedback_system/public/Metrics/goalcompletionrate_meter.dart';
import 'package:feedback_system/public/Metrics/questionandresponse.dart';
import 'package:feedback_system/public/Metrics/satisfaction_rating.dart';
import 'package:feedback_system/public/Metrics/smiley_rating.dart';
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:progress_dialog/progress_dialog.dart';
import 'package:shared_preferences/shared_preferences.dart';

class Answer extends StatefulWidget {
  final String data;

  Answer({this.data});

  @override
  _AnswerState createState() => _AnswerState();
}

class _AnswerState extends State<Answer> {
  var data;
  double avg = 0;
  var attended;
  bool perform = false;
  String email;
  var updated;
  var _doc;
  List<QuestionAndResponse> questionObjectList =
      new List<QuestionAndResponse>();

  instantiate() async {
    await Firestore.instance
        .collection('/feedbacks')
        .document(widget.data)
        .get()
        .then((_data) {
      if (!_data.exists) {
        setState(() {
          data = 'Error';
        });
      } else {
        setState(() {
          data = _data;
        });
      }
    });
  }

  getSharedPreferences() async {
    await SharedPreferences.getInstance().then((val) {
      setState(() {
        email = val.getString("email");
      });
    });
  }

  @override
  void initState() {
    super.initState();
    getSharedPreferences();
    instantiate();
  }

  @override
  Widget build(BuildContext context) {
    double width = MediaQuery.of(context).size.width;
    if (data == null)
      return SpinKitThreeBounce(color: Colors.blue);
    else if (data == 'Error')
      return stopUser('Feedback no longer exists');
    else if (data['attended'].contains(email))
      return stopUser('Can\'t give feedback more than once');
    else
      return fetchDocument(width);
  }

  stopUser(data) {
    return Scaffold(
        body: Center(
      child: Text(data),
    ));
  }

  fetchDocument(double width) {
    return Scaffold(
      appBar: AppBar(
        title: Text(data['name']),
      ),
      body: ListView.separated(
        separatorBuilder: (context, index) =>
            Divider(height: 1.0, color: Colors.grey),
        itemBuilder: (context, index) {
          if (index == data['questions'].length) {
            return Padding(
              padding: const EdgeInsets.all(15.0),
              child: RaisedButton(
                color: Color(0xff23272B),
                child: Text(
                  'Submit',
                  style: TextStyle(color: Colors.white),
                ),
                onPressed: () async {
                  uploadFeedback(context);
                },
              ),
            );
          }
          return Padding(
            padding: EdgeInsets.fromLTRB(5, 2, 5, 2),
            child: Column(
              children: <Widget>[
                ListTile(
                  leading: Text(
                    (index + 1).toString() + ")",
                    style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
                  ),
                  title: Text(
                    data['questions'][index],
                    style: TextStyle(fontSize: 15),
                  ),
                ),
                SizedBox(
                  height: 5,
                ),
                metric(index)
              ],
            ),
          );
        },
        itemCount: data['questions'].length + 1,
      ),
    );
  }

  metric(int index) {
    switch (data['metrics'][index]) {
      case 'Satisfaction':
        return slider(index);
      case 'SmileyRating':
        return smiley(index);
      case 'EffortScore':
        return effortScore(index);
      case 'GoalCompletionRate':
        return goalCompletionRate(index);
      default:
        return Text('Unexpected error');
    }
  }

  goalCompletionRate(int index) {
    QuestionAndResponse temp =
        QuestionAndResponse(data['questions'][index], "GoalCompletionRate");
    questionObjectList.add(temp);
    return GoalCompletionRateMeter(temp);
  }

  effortScore(int index) {
    QuestionAndResponse temp =
        QuestionAndResponse(data['questions'][index], "EffortScore");
    questionObjectList.add(temp);
    return EffortRatingMeter(temp);
  }

  smiley(int index) {
    QuestionAndResponse temp =
        QuestionAndResponse(data['questions'][index], "SmileyRating");
    questionObjectList.add(temp);
    return SmileyRatingMeter(temp);
  }

  slider(int index) {
    QuestionAndResponse temp =
        QuestionAndResponse(data['questions'][index], "Satisfaction");
    questionObjectList.add(temp);
    return SatisafactionRatingMeter(temp);
  }

  uploadFeedback(context) {
    ProgressDialog pr = new ProgressDialog(context);
    pr.style(message: 'Submitting response');
    pr.show();
    var ref = Firestore.instance.collection('/feedbacks').document(widget.data);
    Firestore.instance.runTransaction((transaction) async {
      var doc = await ref.get();
      var prev = doc['scores'];
      attended = doc['attended'];
      attended.add(email);
      print(attended);
      for (int i = 0; i < questionObjectList.length; i++) {
        int response = questionObjectList[i].response;
        prev[i.toString()][response - 1] += 1;
      }
      updated = prev;

      return transaction.update(ref, {
        'scores': updated,
        'attended': attended
      });
    }).then((val) {
      pr.hide();
      Fluttertoast.showToast(msg: 'Feedback submitted successfully');
    }).catchError((e) {
      pr.hide();
      Fluttertoast.showToast(msg: 'Some error occured');
      throw Error();
    });
  }
}

我不知道我是否以正确的方式使用 runTransaction 方法。因为在 Flutter 中使用 Firestore 没有合适的文档。

提前致谢!

标签: firebaseflutterdartgoogle-cloud-firestore

解决方案


推荐阅读