不是类型转换中自定义类的子类型。从 Firestore 中检索地图数组,java,flutter,dart,google-cloud-firestore"/>

首页 > 解决方案 > _InternalLinkedHashMap不是类型转换中自定义类的子类型。从 Firestore 中检索地图数组

问题描述

我将来自自定义类“PollOption”的数据作为地图数组存储在 Firestore 中。当我尝试检索数据时,出现此错误

_InternalLinkedHashMap<String, dynamic> is not a subtype of 'PollOption' in type cast.

我的其他数据检索正常。

我的模型被存储到一个集合中。PollOption 嵌套在此:

class Question{
  //single values
  final Timestamp askedOn;
  final String chosenAnswer;
  final String askedBy;
 ...

  //arrays
  final List<String> categories;
  final List<String> declinedUsers;
  final List<PollOption> pollOptions;
 ...


  Question({
    this.askedBy,
    this.askedByAvatar,
    this.askedByName,

...

    this.pollOptions,
    this.starredMessages,

...

  });

我的 PollOption 模型:

class PollOption{
  final String option;
  final bool selected;
  final int optionNumber;
  final int votes;

  PollOption({this.option, this.optionNumber, this.selected, this.votes});
}

我如何将数据存储到 Firestore:

Future createQuestion(Question data) async {
    ...

    List<Map> sterilizedPolls (){
      List<Map> polls = [];
      if(data.pollOptions != null){
      data.pollOptions.forEach((PollOption pollOption){
        Map option ={
          'option': pollOption.option,
          'votes': pollOption.votes,
          'optionNumber': pollOption.optionNumber,
          'selected': pollOption.selected,
        };
        polls.add(option);
      });

      }
      return polls;

    }


    return await questionCollection.add({ 
    'askedBy': uid,
...
    'declinedUsers': [],
    'pollOptions': sterilizedPolls(),

...


    });

  }

我如何检索数据:

//Getting all the questions I want
Future<List<Question>> getOpenQuestions() async{
    final QuerySnapshot result = await questionCollection
      .where('locked', isEqualTo: false)
      .where('chosenAnswer', isEqualTo: '')
      .getDocuments();
    final List<DocumentSnapshot> documents = result.documents;
    final List<Question> openQuestions = [];
   documents.forEach((data){
     print('accessing database');
      openQuestions.add(
        Question(
          question: data['question'],

        )
      );
    });

    return openQuestions;
  }

//Creating list from snapshot
List<Question> _questionListFromSnapshot(QuerySnapshot snapshot) {



    return snapshot.documents.map((doc){

      return Question(
        askedBy: doc.data['askedBy'] ?? '',
        askedByName: doc.data['askedByName'] ?? 'Anonymous',

     ...

        pollOptions: List.from(doc.data['pollOptions']).cast<PollOption>() ?? [],

       ...

      );
    }).toList();





  }

//creating stream
   Stream<List<Question>> get openQuestionList {
     try {
      return questionCollection
      .where('locked', isEqualTo: false)
      .snapshots()
      .map(_questionListFromSnapshot);

     } catch (e) {
       return e;
     }

  }

以及我如何显示数据:

class OpenQuestions extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    final openQuestions = Provider.of<List<Question>>(context) ?? [];

    return StreamBuilder<List<Question>>(
        stream: QuestionDatabaseService().openQuestionList,
        builder: (context, snapshot){
          if(snapshot.hasError){
            return Text('Error!');
          }
          if (snapshot.hasData){
              return ListView.builder(
                itemCount: openQuestions.length,
                itemBuilder: (context, index) {
                  return QuestionTile(question: openQuestions[index], context: context);
                },
              );
          }else{
            return Loading();
          }

        }

        );

//The QuestionTile Loaded

class QuestionTile extends StatelessWidget {

  final Question question;
  final context;

  QuestionTile({this.question, this.context});

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: EdgeInsets.all(10.0),
      child: Card(
        child: ListTile(
         ...
          title: Text(question.question),
          subtitle: question.poll == false ? Text(question.message) : Text('Poll'),
          onTap: (){
            _showBottomModal(context, question);
          },
        ),
      ),

    );
  }
}

//The bottom modal that pops up
void _showBottomModal(context, question)async {
  showModalBottomSheet(context: context, isScrollControlled: true, builder: (context){
    return Container(
      //color: Color(0xFF737373),
      child: Container(
        child: FractionallySizedBox(

//Where the problem widget is being called

          child: AnswerQuestion(question: question),
          heightFactor: 0.90,
          ),
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.only(
            topLeft: const Radius.circular(30.0),
            topRight: const Radius.circular(30.0),
          )
        ),

      ),
    );
  });
}

//AnswerQuestion widget where the error is occurring

class _AnswerQuestionState extends State<AnswerQuestion> {

...



  @override
  Widget build(BuildContext context) {



    return Container(

      child:Column(
        mainAxisAlignment: MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[
...
          Form(
            key: _formKey,
            child: Column(
              children: [
//Where the data is being displayed with error

                ConstrainedBox(
                constraints: BoxConstraints(
                 maxHeight: 300.0
                 ),
              child: Container(
               child: ListView.builder(
                    itemCount: widget.question.pollOptions.length,
                   itemBuilder: (BuildContext context, int index){



                   return ListTile(
                      title: Text(widget.question.pollOptions[index].option),
                     leading: Radio(
                     value: widget.question.pollOptions[index].optionNumber, 
                      groupValue: _optionSelected, 
                      onChanged: _handleRadioValueChange,
                   ),
                 );

                ...

抱歉,如果代码太多(或不够),我仍在学习 Flutter 并希望提供尽可能多的帮助来解决此错误。

标签: javaflutterdartgoogle-cloud-firestore

解决方案


问题出在这条线上:

pollOptions: List.from(doc.data['pollOptions']).cast<PollOption>() ?? [],

in 中的值doc.data['pollOptions']实际上是 JSON 数据,在 dart 中表示为Map<String, dynamic>. Dart 不知道如何自动将 Map 转换为您的对象PollOption

考虑一下:

pollOptions: doc.data['pollOptions'].map((Map<String, dynamic> json) => PollOption.fromJson(json)).toList()

这是假设doc.data['pollOptions']返回一个 List 如果它是 JSON 数组则应该这样做。

当然fromJson,您的班级需要一个工厂构造函数PollOption

class PollOption {
...
   factory PollOption.fromJson(final Map<String, dynamic> json) {
      return PollOption(json["optionkey"], etc);
   }
...
}

推荐阅读