Сложные модели с json_serializable - список <objects>не конвертируется в карту - PullRequest
0 голосов
/ 09 марта 2020

ОБНОВЛЕНИЕ Я создал небольшой пример и добавлю весь код в этот пост. Я должен верить, что есть ответ / объяснение этому, и я надеюсь, что кто-то может рассказать мне о том, что я скучаю. Поля классов, которые являются объектами типа, не конвертируются, и я не понимаю, почему.

Вот классы моделей, с которыми я работаю.

import 'package:json_annotation/json_annotation.dart';

part 'parent.g.dart';

@JsonSerializable()
class Parent {
  int id;
  final String name;
  final int age;
  List<Child> children;
  Job job;

  Parent({this.name, this.age, this.children, this.job});

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

  Map<String, dynamic> toJson() => _$ParentToJson(this);
}

@JsonSerializable()
class Child{
  int id;
  final String name;
  final int age;

  Child({this.name, this.age});

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

  Map<String, dynamic> toJson() => _$ChildToJson(this);
}

@JsonSerializable()
class Job{
  int id;
  String title;

  Job({this.title});

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

  Map<String, dynamic> toJson() => _$JobToJson(this);
}

Вот сгенерированный файл .g для этих классов

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'parent.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

Parent _$ParentFromJson(Map<String, dynamic> json) {
  return Parent(
    name: json['name'] as String,
    age: json['age'] as int,
    children: (json['children'] as List)
        ?.map(
            (e) => e == null ? null : Child.fromJson(e as Map<String, dynamic>))
        ?.toList(),
    job: json['job'] == null
        ? null
        : Job.fromJson(json['job'] as Map<String, dynamic>),
  )..id = json['id'] as int;
}

Map<String, dynamic> _$ParentToJson(Parent instance) => <String, dynamic>{
      'id': instance.id,
      'name': instance.name,
      'age': instance.age,
      'children': instance.children,
      'job': instance.job,
    };

Child _$ChildFromJson(Map<String, dynamic> json) {
  return Child(
    name: json['name'] as String,
    age: json['age'] as int,
  )..id = json['id'] as int;
}

Map<String, dynamic> _$ChildToJson(Child instance) => <String, dynamic>{
      'id': instance.id,
      'name': instance.name,
      'age': instance.age,
    };

Job _$JobFromJson(Map<String, dynamic> json) {
  return Job(
    title: json['title'] as String,
  )..id = json['id'] as int;
}

Map<String, dynamic> _$JobToJson(Job instance) => <String, dynamic>{
      'id': instance.id,
      'title': instance.title,
    };

Вот класс DAO для родительского класса

import 'package:sembast/sembast.dart';

import 'package:json_serial_test/services/app_database.dart';
import 'package:json_serial_test/models/parent.dart';

class ParentDao {
  static const String PARENT_STORE_NAME = 'parents';
  // A Store with int keys and Map<String, dynamic> values.
  // This Store acts like a persistent map, values of which are Parent objects converted to Map
  final _parentStore = intMapStoreFactory.store(PARENT_STORE_NAME);

  // Private getter to shorten the amount of code needed to get the
  // singleton instance of an opened database.
  Future<Database> get _db async => await AppDatabase.instance.database;

  Future insert(Parent parent) async {
    await _parentStore.add(await _db, parent.toJson());
  }

  Future update(Parent parent) async {
    // For filtering by key (ID), RegEx, greater than, and many other criteria,
    // we use a Finder.
    final finder = Finder(filter: Filter.byKey(parent.id));
    await _parentStore.update(
      await _db,
      parent.toJson(),
      finder: finder,
    );
  }

  Future deleteAll() async {
    await _parentStore.delete(await _db);
  }

  Future delete(Parent parent) async {
    final finder = Finder(filter: Filter.byKey(parent.id));
    await _parentStore.delete(
      await _db,
      finder: finder,
    );
  }

  Future<List<Parent>> getAllSortedByName() async {
    // Finder object can also sort data.
    final finder = Finder(sortOrders: [
      SortOrder('name'),
    ]);

    final recordSnapshots = await _parentStore.find(
      await _db,
      finder: finder,
    );

    // Making a List<Parent> out of List<RecordSnapshot>
    return recordSnapshots.map((snapshot) {
      final parent = Parent.fromJson(snapshot.value);
      // An ID is a key of a record from the database.
      parent.id = snapshot.key;
      return parent;
    }).toList();
  }
}

Вот мой тест

// Setup
          final k1 = Child(name: 'Billy', age: 10);
          final k2 = Child(name: 'Jannet', age: 9);
          final job = Job(title: 'Cook');
          final List<Child> kids = [k1, k2];

          final dad = Parent(name: 'Dave', age: 52, job: job, children: kids);

          await pDao.insert(dad);

          List<Parent> dadsInDb = await pDao.getAllSortedByName();

          print('Dads from DB: ${dadsInDb.toString()}');

При попытке вставить Parent в мою базу данных Sembast, это ошибка, которая появляется.

E/flutter (12986): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: Invalid argument(s): value Instance of 'Child' unsupported type Child E/flutter (12986): #0      cloneValue (package:sembast/src/utils.dart:191:3) E/flutter (12986): #1      cloneValue.<anonymous closure> (package:sembast/src/utils.dart:177:33) E/flutter (12986): #2      MappedListIterable.elementAt (dart:_internal/iterable.dart:417:29) E/flutter (12986): #3      ListIterable.toList (dart:_internal/iterable.dart:221:19) E/flutter (12986): #4      cloneValue (package:sembast/src/utils.dart:177:52) E/flutter (12986): #5      cloneValue.<anonymous closure> (package:sembast/src/utils.dart:174:49) E/flutter (12986): #6      MapMixin.map (dart:collection/maps.dart:165:28) E/flutter (12986): #7  cloneValue (package:sembast/src/utils.dart:173:18) E/flutter (12986):
#8      SembastStore.txnPutSync (package:sembast/src/store_impl.dart:133:15) E/flutter (12986): #9     SembastStore.txnAdd (package:sembast/src/store_impl.dart:117:11) E/flutter (12986): <asynchronous suspension> E/flutter (12986): #10    StoreRefMixin.add.<anonymous closure> (package:sembast/src/store_ref_impl.dart:75:12) E/flutter (12986): #11 SembastDatabase.inTransaction.<anonymous closure> (package:sembast/src/database_impl.dart:1238:34) E/flutter (12986):
#12     SembastDatabase.transaction.<anonymous closure>.<anonymous closure> (package:sembast/src/database_impl.dart:1090:59) E/flutter (12986): #13     new Future.sync (dart:async/future.dart:224:31) E/flutter (12986): #14     SembastDatabase.transaction.<anonymous closure> (package:sembast/src/database_impl.dart:1090:26) E/flutter (12986): #15     BasicLock.synchronized (package:synchronized/src/basic_lock.dart:32:26) E/flutter (12986):
#16     SembastDatabase.transaction (package:sembast/src/database_impl.dart:1073:38) E/flutter (12986):
#17     SembastDatabase.inTransaction (package:sembast/src/database_impl.dart:1238:7) E/flutter (12986): #18 StoreRefMixin.add (package:sembast/src/store_ref_impl.dart:72:25) E/flutter (12986): #19     ParentDao.insert (package:json_serial_test/data/parent_dao.dart:17:24) E/flutter (12986): <asynchronous suspension> E/flutter (12986): #20    
_MyHomePageState.build.<anonymous closure> (package:json_serial_test/main.dart:120:22) E/flutter (12986): #21    
_InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:706:14) E/flutter (12986):
#22     _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:789:36) E/flutter (12986):
#23     GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24) E/flutter (12986): #24     TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:486:11) E/flutter (12986): #25  BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:264:5) E/flutter (12986): #26   BaseTapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:236:7) E/flutter (12986): #27   GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:156:27) E/flutter (12986):
#28     GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:222:20) E/flutter (12986):
#29     GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:198:22) E/flutter (12986):
#30     GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:156:7) E/flutter (12986):
#31     GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:102:7) E/flutter (12986):
#32     GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:86:7) E/flutter (12986):
#33     _rootRunUnary (dart:async/zone.dart:1138:13) E/flutter (12986): #34     _CustomZone.runUnary (dart:async/zone.dart:1031:19) E/flutter (12986): #35     _CustomZone.runUnaryGuarded (dart:async/zone.dart:933:7) E/flutter (12986): #36     _invoke1 (dart:ui/hooks.dart:273:10) E/flutter (12986): #37    
_dispatchPointerDataPacket (dart:ui/hooks.dart:182:5) E/flutter (12986):

Если кто-то могли бы помочь мне показать, что я пропустил, сделал неправильно, я был бы очень признателен.

ОРИГИНАЛЬНЫЙ ПОЧТА ============ == Должен ли json_serializable преобразовать ВЕСЬ класс в JSON, или есть ли ограничения, на которые я нахожусь?

Я решил попытаться решить множество проблем, которые я сам вызвал, с помощью json_serializable для создания методов to Json и Json, необходимых для работы с NoSQL DB.

Если я создаю класс, который включает в себя поле List<Ojb>, сгенерированный код, по-видимому, приводит к JSON для каждого поля класса, но не может сделать это для объектов в списке.

Простой пример

class Parent {
  final int age;
  final String name;
  List<Child> children;

  Parent({this.age, this.name, this.children});

}

class Child {
  final int age;
  final String name;

  Child({this.age, this.name});
}

Когда я использую json_serializable, который, кажется, прекрасно работает, я получаю методы Json и Json для вышеупомянутых классов. На первый взгляд все выглядит идеально.

Когда я пытаюсь вставить Parent (содержащий дочерние элементы) в мою базу данных No SQL, вставка не может сказать, что тип (ссылающийся на дочерний объект) не поддерживается - Верное утверждение, с этим проблем не возникает.

Когда я прохожу через это через отладчик, вот что я вижу.

Parent преобразуется в возраст карты, отображаемый в качестве ключа с его значением имя отображается как ключ с его значением

До этого момента я вижу, что все является картой [.. и все выглядит великолепно

Затем мы попадаем в список Дочерних объектов.

Эта часть не преобразуется в карту, но все еще существует в виде списка дочерних объектов, что означает сбой вставки.

Оба класса имеют аннотацию jsonSerializable Оба классы генерируют ожидаемый код (часть), классы

Все работает отлично, пока я не пытаюсь использовать List<myObject> в одном из моих классов.

Вся причина можно было бы использовать пакет вроде json_serializable полагается на код, который автоматически генерируется, и не должен создавать его сам. Я не хочу вручную обновлять автоматически сгенерированный код, чтобы решить эту проблему, поэтому я не вставил код. Если это ответ, то я пойду другим путем.

Мой вопрос: есть ли какая-то конфигурация, которую я пропускаю или, возможно, делаю неправильно, что позволило бы ВСЕМ элементам в классе быть преобразованным в map / json, даже если поля класса не просто простые типы int и string. Я ожидаю, что у меня может быть класс, который включает в себя примитивы, наряду с объектами, списки объектов и т. Д. c. и все должно генерироваться правильно или нет?

1 Ответ

0 голосов
/ 12 марта 2020

После многих испытаний и перестроений я решил эту проблему, и теперь, похоже, все работает с моей базой данных Sembast, используя json_serializable для моих классов моделей. Возможно, были и другие факторы, которые способствовали моему успеху, но я думаю, что основным отличием было добавление следующего параметра в аннотацию JSONSerializable класса Parent. это код, если он помогает кому-то еще.

@JsonSerializable(explicitToJson: true)
class Parent {
  int id;
  final String name;
  final int age;
  List<Child> children;
  Job job;

  Parent({this.name, this.age, this.children, this.job});

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

  Map<String, dynamic> toJson() => _$ParentToJson(this);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...