Can someone confirm if SQFLite supports maps containing maps? I did run across the following post on this site and possibly this is the answer?
Flutter sqflite insert List<String>
In my situation, I have a two model classes I am working with.
House
Dog
House includes a field called pets which is a List
I have a constructor and factory method in each of these classes which takes care of converting to/from map/object as needed for sending to and retrieving information from SQFLite.
Model classes
Dog
class Dog {
final int id;
final String breed;
final String name;
final int age;
Dog({this.id, this.breed, this.name, this.age});
// Used when inserting a row into the db, including the id field
Map<String, dynamic> toMap() {
final map = Map<String, dynamic>();
map['id'] = id;
map['breed'] = breed;
map['name'] = name;
map['age'] = age;
return map;
}
// Used when returning a row from the DB and converting into an object
factory Dog.fromMap(Map<String, dynamic> data) => Dog(
id: data['id'],
breed: data['breed'],
name: data['name'],
age: data['age']
);
}
House
import 'dog.dart';
class House{
final int id;
final String name;
final String color;
final List<Dog> pets;
House({this.id, this.name, this.color, this.pets});
// Will be used when inserting a row into the database
Map<String, dynamic> toMap() {
final map = Map<String, dynamic>();
map['id'] = id;
map['name'] = name;
map['color'] = color;
if (this.pets != null) {
map['pets'] = this.pets.map((pet) => pet.toMap()).toList();
}
return map;
}
// Used when returning a row from the DB and converting into an object
factory House.fromMap(Map<String, dynamic> data) {
return House(
id: data['id'],
name: data['name'],
color: data['color'],
pets: data['pets'] != null
? (data['pets'] as List).map((pet) => Dog.fromMap(pet)).toList()
: null,
);
}
}
Method for inserting a new house
Future<int> addNewHome(House house) async {
// Attempt to add the house to the DB
var client = await database.db;
int result = await client.insert(HomesSchema.tblHomes, house.toMap(), conflictAlgorithm: ConflictAlgorithm.replace);
_homes.add(house);
return result;
}
When I attempt to perform the insert, I get the following error.
E/flutter ( 586): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: DatabaseException(java.util.HashMap cannot be cast to java.lang.Integer) sql 'INSERT OR REPLACE INTO homes (id, name, color, pets) VALUES (?, ?, ?, ?)' args [1, Smith, Green, [{name: Mackie, id: 1, breed: Rottweiler, age: 8}, {name: Tanner, id: 2, breed: Mastiff, age: 8}]]}
E/flutter ( 586): #0 wrapDatabaseException (package:sqflite/src/exception_impl.dart:12:7)
E/flutter ( 586): <asynchronous suspension>
E/flutter ( 586): #1 SqfliteDatabaseFactoryImpl.wrapDatabaseException (package:sqflite/src/factory_impl.dart:25:7)
E/flutter ( 586): #2 SqfliteDatabaseMixin.safeInvokeMethod (package:sqflite/src/database_mixin.dart:188:15)
E/flutter ( 586): #3 SqfliteDatabaseMixin.txnRawInsert.<anonymous closure> (package:sqflite/src/database_mixin.dart:363:14)
E/flutter ( 586): #4 SqfliteDatabaseMixin.txnSynchronized.<anonymous closure> (package:sqflite/src/database_mixin.dart:307:22)
E/flutter ( 586): #5 BasicLock.synchronized (package:synchronized/src/basic_lock.dart:32:26)
E/flutter ( 586): #6 SqfliteDatabaseMixin.txnSynchronized (package:sqflite/src/database_mixin.dart:303:43)
E/flutter ( 586): #7 SqfliteDatabaseMixin.txnWriteSynchronized (package:sqflite/src/database_mixin.dart:325:7)
E/flutter ( 586): #8 SqfliteDatabaseMixin.txnRawInsert (package:sqflite/src/database_mixin.dart:362:12)
E/flutter ( 586): #9 SqfliteDatabaseExecutorMixin.rawInsert (package:sqflite/src/database_mixin.dart:49:15)
E/flutter ( 586): #10 SqfliteDatabaseExecutorMixin.insert (package:sqflite/src/database_mixin.dart:59:12)
E/flutter ( 586): #11 Homes.addNewHome (package:search_list_view/providers/homes.dart:19:31)
E/flutter ( 586): <asynchronous suspension>
E/flutter ( 586): #12 _MyAppState.build.<anonymous closure> (package:search_list_view/main.dart:95:26)
E/flutter ( 586): #13 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:706:14)
E/flutter ( 586): #14 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:789:36)
E/flutter ( 586): #15 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
E/flutter ( 586): #16 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:486:11)
E/flutter ( 586): #17 BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:264:5)
E/flutter ( 586): #18 BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:199:7)
E/flutter ( 586): #19 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:467:9)
E/flutter ( 586): #20 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:76:12)
E/flutter ( 586): #21 PointerRouter._dispatchEventToRoutes.<anonymous closure> (package:flutter/src/gestures/pointer_router.dart:117:9)
E/flutter ( 586): #22 _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:379:8)
E/flutter ( 586): #23 PointerRouter._dispatchEventToRoutes (package:flutter/src/gestures/pointer_router.dart:115:18)
E/flutter ( 586): #24 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:101:7)
E/flutter ( 586): #25 GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:218:19)
E/flutter ( 586): #26 GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:198:22)
E/flutter ( 586): #27 GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:156:7)
E/flutter ( 586): #28 GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:102:7)
E/flutter ( 586): #29 GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:86:7)
E/flutter ( 586): #30 _rootRunUnary (dart:async/zone.dart:1138:13)
E/flutter ( 586): #31 _CustomZone.runUnary (dart:async/zone.dart:1031:19)
E/flutter ( 586): #32 _CustomZone.runUnaryGuarded (dart:async/zone.dart:933:7)
E/flutter ( 586): #33 _invoke1 (dart:ui/hooks.dart:273:10)
E/flutter ( 586): #34 _dispatchPointerDataPacket (dart:ui/hooks.dart:182:5)
E/flutter ( 586):
If the answer is to change my DB schema so I have a table which joins dogs and houses and then do a custom query to pull back the information I'm after, then fine, I will do that. It doesn't seem too far fetch that a nosql db should be able to handle this... yes/no?
Any assistance would be much appreciated.
Thank you,
Bob
For storing any kind of value in the SQLite Database you can simply serialize the object into a JSON string and later deserialize the object.
lets say you have a class called Menu. (I am using JSON serializable here)
class Menu {
#JsonKey(name: "status")
String status;
#JsonKey(name: "data")
MenuListData menuListData;
Menu(this.status, this.menuListData);
factory Menu.fromJson(Map<String,dynamic>
json)=>_$MenuFromJson(json);
Map<String, dynamic> toJson() => _$MenuToJson(this);
}
Here is how to encode it in JSON and store it(in your bloc).
Menue menuList =
await getIt<LiveMenuRepository>().getMenuResponse(menuPost);
//decode the response to String format
String menuResponseString = jsonEncode(menuList);
//convert the string to Map of <String,dynamic> format
Map<String, dynamic> menuResponseMap = {"menu": menuResponseString};
//store this Map response in to local database
int menuStored = await getIt<LocalMenuRepository>().insertMenuResponseData(menuResponseMap);
Your DB insertion method
Future<int> insertMenuResponseData(Map<String,dynamic> menuResponse) async {
final db = await dbProvider.database;
var result = db.insert(menuTable, menuResponse);
return result;
}
Later retrieve your object using this
final Map<String, dynamic> menuList = await getIt<LocalMenuRepository>().getMenuResponseString();
// if(menuList!=null) {
menuList.forEach((key, value) {
if (key == "menu") {
storedMenu = value ;
}
});
//decode the string back to Map Object
final dynamic menuMap = jsonDecode(storedMenu);
//getting the Menu object using fromJson method
final Menu menuListNameResponse = Menu
.fromJson(menuMap as Map<String,dynamic>);
//getMenuResponseString method in db
Future<Map<String,dynamic>> getMenuResponse() async {
final db = await dbProvider.database;
List<Map<String, dynamic>> result;
result = await db.rawQuery('SELECT * FROM $menuTable');
// print(result[0]);
if (result.length > 0) {
return result[0];
}
return null;
}
Supported types are listed here (num, String or Uint8List): https://github.com/tekartik/sqflite/blob/master/sqflite/doc/supported_types.md
Nested content is not supported, Map and List should be encoded in a supported type for example as json string.
Related
I'm studying flutter with Sqflite and trying to make a small app, but I'm getting this error when I run the code, I've looked literaly everywhere to findout what it could be.
Here the code code who use the Sqflite package:
Future<Database> getDatabase() async {
final String path = join(await getDatabasesPath(), 'bytebank.db');
return openDatabase(path, onCreate: (db, version) {
db.execute('CREATE TABLE contacts'
'(id INTEGER PRIMARY KEY, '
'name TEXT, '
'account_number INTEGER)');
}, version: 1);
}
Future<int> save(Contact contact) async {
final Database db = await getDatabase();
final Map<String, dynamic> contactMap = Map();
contactMap['name'] = contact.name;
contactMap['account_number'] = contact.account;
contactMap['id'] = contact.id;
return db.insert('contacts', contactMap);
}
Future<List<Contact>> findAll() async {
final Database db = await getDatabase();
final List<Map<String, dynamic>> result = await db.query('contacts');
final List<Contact> contacts = [];
for (Map<String, dynamic> row in result) {
final Contact contact = Contact(
row['id'],
row['name'],
row['account_number'],
);
contacts.add(contact);
}
return contacts;
}
And here is the only one place where I use This functions:
void main() {
save(Contact('William', 2, 13456)).then((id) {
findAll().then((contacts) => print(contacts));
});
runApp(ByteBankApp());
}
Model Class:
class Contact {
final String name;
final int account;
final int id;
Contact( this.id,
this.name,
this.account,
);
#override
String toString() {
return 'Contact{name: $name, account: $account}';
}
}
Error Trace back:
Launching lib\main.dart on sdk gphone x86 arm in debug mode...
Running Gradle task 'assembleDebug'...
√ Built build\app\outputs\flutter-apk\app-debug.apk.
Installing build\app\outputs\flutter-apk\app.apk...
Debug service listening on ws://127.0.0.1:52296/07rtnvW9tlQ=/ws
Syncing files to device sdk gphone x86 arm...
E/flutter (28649): [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: Null check operator used on a null value
E/flutter (28649): #0 MethodChannel.binaryMessenger (package:flutter/src/services/platform_channel.dart:142:86)
E/flutter (28649): #1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:148:36)
E/flutter (28649): #2 MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:331:12)
E/flutter (28649): #3 invokeMethod (package:sqflite/src/sqflite_impl.dart:17:13)
E/flutter (28649): #4 SqfliteDatabaseFactoryImpl.invokeMethod (package:sqflite/src/factory_impl.dart:82:7)
E/flutter (28649): #5 SqfliteDatabaseFactoryMixin.safeInvokeMethod.<anonymous closure> (package:sqflite_common/src/factory_mixin.dart:41:38)
E/flutter (28649): #6 wrapDatabaseException (package:sqflite/src/exception_impl.dart:7:32)
E/flutter (28649): #7 SqfliteDatabaseFactoryImpl.wrapDatabaseException (package:sqflite/src/factory_impl.dart:78:7)
E/flutter (28649): #8 SqfliteDatabaseFactoryMixin.safeInvokeMethod (package:sqflite_common/src/factory_mixin.dart:41:7)
E/flutter (28649): #9 SqfliteDatabaseFactoryMixin.getDatabasesPath (package:sqflite_common/src/factory_mixin.dart:153:26)
E/flutter (28649): #10 getDatabasesPath (package:sqflite/sqflite.dart:161:54)
E/flutter (28649): #11 getDatabase (package:bytebank/database/app_database.dart:6:34)
E/flutter (28649): #12 save (package:bytebank/database/app_database.dart:16:29)
E/flutter (28649): #13 main (package:bytebank/main.dart:7:3)
E/flutter (28649): #14 _runMainZoned.<anonymous closure>.<anonymous closure> (dart:ui/hooks.dart:142:25)
E/flutter (28649): #15 _rootRun (dart:async/zone.dart:1354:13)
E/flutter (28649): #16 _CustomZone.run (dart:async/zone.dart:1258:19)
E/flutter (28649): #17 _runZoned (dart:async/zone.dart:1789:10)
E/flutter (28649): #18 runZonedGuarded (dart:async/zone.dart:1777:12)
E/flutter (28649): #19 _runMainZoned.<anonymous closure> (dart:ui/hooks.dart:138:5)
E/flutter (28649): #20 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:283:19)
E/flutter (28649): #21 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
E/flutter (28649):
I am not sure if will help, but I was running into a similar issue when initializing a database in an async "main" method. Adding the following:
WidgetsFlutterBinding.ensureInitialized();
inside the method before the code initializing the database solved the problem.
I am trying to add WooCommerce payment gateways through WooCommerce plugin on flutter, I've been having an error related to it, and I'm pretty sure that it's the package's fault.
I'd really like any kind of help related to it, since I am stuck on it, The error points at the order "int". I changed it to string still gave me the same error.
Here's the code---
Method:
WooCommerce wooCommerce = WooCommerce(
baseUrl: baseUrl,
consumerKey: consumerKey,
consumerSecret: consumerSecret,
isDebug: true,
);
getPaymentGateways() async {
gateways = await wooCommerce.getPaymentGateways();
}
Error-
E/flutter (13771): #0 new WooPaymentGateway.fromJson (package:woocommerce/models/payment_gateway.dart:62:5)
E/flutter (13771): #1 WooCommerce.getPaymentGateways (package:woocommerce/woocommerce.dart:1413:39)
E/flutter (13771): <asynchronous suspension>
E/flutter (13771): #2 _CheckoutCardState.getPaymentGateways (package:flutter_auth/to_test/checkout.dart:34:34)
E/flutter (13771): #3 _CheckoutCardState.build.<anonymous closure> (package:flutter_auth/to_test/checkout.dart:100:23)
E/flutter (13771): #4 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:779:19)
E/flutter (13771): #5 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:862:36)
E/flutter (13771): #6 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
E/flutter (13771): #7 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:504:11)
E/flutter (13771): #8 BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:282:5)
E/flutter (13771): #9 BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:217:7)
E/flutter (13771): #10 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:475:9)
E/flutter (13771): #11 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:76:12)
E/flutter (13771): #12 PointerRouter._dispatchEventToRoutes.<anonymous closure> (package:flutter/src/gestures/pointer_router.dart:122:9)```
WooPaymentGateway-
String id;
String title;
String description;
int order;
bool enabled;
String methodTitle;
String methodDescription;
List<String> methodSupports;
WooPaymentGatewaySettings settings;
WooPaymentGatewayLinks lLinks;
WooPaymentGateway(
{this.id,
this.title,
this.description,
this.order,
this.enabled,
this.methodTitle,
this.methodDescription,
this.methodSupports,
this.settings,
this.lLinks}) : assert (id != null);
WooPaymentGateway.fromJson(Map<String, dynamic> json) {
id = json['id'];
title = json['title'];
description = json['description'];
order = json['order'];
enabled = json['enabled'];
methodTitle = json['method_title'];
methodDescription = json['method_description'];
methodSupports = json['method_supports'].cast<String>();
settings = json['settings'] != null
? new WooPaymentGatewaySettings.fromJson(json['settings'])
: null;
lLinks = json['_links'] != null ? new WooPaymentGatewayLinks.fromJson(json['_links']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['title'] = this.title;
data['description'] = this.description;
data['order'] = this.order;
data['enabled'] = this.enabled;
data['method_title'] = this.methodTitle;
data['method_description'] = this.methodDescription;
data['method_supports'] = this.methodSupports;
if (this.settings != null) {
data['settings'] = this.settings.toJson();
}
if (this.lLinks != null) {
data['_links'] = this.lLinks.toJson();
}
return data;
}
}
Let me know if I post the thing wrong<////>>??/////<<>>///
UPDATE
I have built a small sample and will add all code to this post. I have to believe there is an answer/explanation to this and am hoping someone can educate me on what I'm missing. Class fields that are type object are not getting converted and I do not understand why.
Here are the model classes I'm working with.
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);
}
Here is the .g generated file for these classes
// 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,
};
Here is the DAO class for the parent class
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();
}
}
Here is my test
// 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()}');
Upon trying to perform an insert of a Parent into my sembast DB, this is the error that shows up.
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):
If someone could please assist me in showing what I've missed, done incorrectly, I would greatly appreciate it.
ORIGINAL POST
==============
Should json_serializable convert ALL of a class to JSON, or are there limitations that I am hitting?
I have decided to try and resolve a slew of issues I've caused myself by using json_serializable to create the toJson and fromJson methods needed for working with a NoSQL DB.
If I create a class which includes a field that is a List<Ojb>, the generated code seems to result in JSON for each field of the class but fails to do so for the objects in the list.
Simple example
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});
}
When I use json_serializable, which seems to work beautifully, I get my toJson and fromJson methods for the above mentioned classes. At first glance, everything looks perfect.
When I attempt to insert a Parent (containing children) into my NoSQL DB, the insert fails to say that the type (referencing the Child object) is not supported - True statement, have no issues with that.
When I step through this via the debugger, here is what I am seeing.
Parent is converted to map
age shows up as key with its value
the name shows up as key with its value
Up to this point, I can see that everything is a map[.. and all looks great
Then we get to the list of Child objects.
This part is not converted to a map but still exists as a list of Child objects, hence the failure of the insert.
Both classes have the jsonSerializable annotation
Both classes are generating the expected code (part of), classes
Everything works perfectly as long as I don't try to use a List<myObject> in one of my classes.
The entire reason one would use a package like json_serializable is to rely on the code that is automatically generated and not have to build it myself. I don't want to have to manually update automatically generated code to resolve this, which is why I have not pasted in the code. If that's the answer, then I'll take a different route.
My question is... is there some configuration that I am missing or possibly doing incorrectly that would allow ALL items within the class to be converted to map/json, even when the fields of a class are not just simple int and string types. I would expect that I could have a class which includes primitives, along with objects, Lists of objects, etc. and everything should generate correctly, or no?
After many trials and rebuilds, I have resolved this issue and everything appears to be working now with my Sembast DB using json_serializable for my model classes. Possibly there were other factors that contributed to my success, but I think the main difference was adding the following parameter to the JSONSerializable annotation of the Parent class.
explicitToJson: true
Here is the code, in the event it helps somebody else out there.
The full explanation you can find here https://flutter.dev/docs/development/data-and-backend/json
#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);
}
I want to fetch details of a product by retrieving its ID and by accessing its Id to load the details needed but I keep getting an error that I dont quite understand?
here is my provider data:
class AddCar {
int id;
String name;
String city;
String country;
String currencyT;
double price;
String date;
int sponsNum;
String category;
String company;
String model;
String year;
String engine;
double distanceCovered;
String transmission;
String oilT;
String outColor;
String inColor;
String description;
File image;
PlaceLocation location;
bool isFavorite;
AddCar({
this.id,
this.name,
this.city,
this.country,
this.currencyT,
this.price,
this.date,
this.sponsNum,
this.category,
this.company,
this.model,
this.year,
this.engine,
this.distanceCovered,
this.transmission,
this.oilT,
this.outColor,
this.inColor,
this.description,
this.image,
this.location,
this.isFavorite = false,
});
}
class PlaceLocation {
final double latitude;
final double longitude;
final String address;
const PlaceLocation({
this.address,
this.latitude,
this.longitude,
});
}
Here is how im fetching the data (i have a link to a custome ID that im clicking on to lead to that product):
Future<void> fetchAndSetCarDetails() async {
const url = 'customLink/Detail?Id=204';
final response = await http.get(url);
final extractedData = json.decode(response.body) as Map<String, dynamic>;
List<AddCar> loadedCars = [];
extractedData.forEach((carId, carData) {
loadedCars.add(AddCar(
id: int.parse(carId),
name: carData['adTitle'],
sponsNum: carData['adNumber'],
price: carData['adPrice'],
date: carData['adDate'],
model: carData['brandModel'],
year: carData['modelYear'],
distanceCovered: carData['kilometer'],
transmission: carData['gearType'],
oilT: carData['fuelType'],
location: carData['adLocation'][PlaceLocation(
address: carData['adAddress'],
latitude: carData['lath'],
longitude: carData['lang'],
)],
description: carData['adDetails'],
country: carData['country'],
city: carData['cityName'],
category: carData['category'],
company: carData['brand'],
engine: carData['cylinder'],
outColor: carData['exteriorColor'],
inColor: carData['interiorColor'],
));
});
_cars = loadedCars;
print(response.body);
notifyListeners();
}
Here is the print data I get:
I/flutter (13626): {"id":204,"adTitle":null,"adDate":"2019-11-07T11:52:40.0156875","adPrice":25.0,"adNumber":195,"adAddress":"AdAddressssssss","adLocation":{"lath":"40.959028921030104","lang":" 30.992774628906318"},"adDetails":null,"country":227,"cityName":"Stockholm","category":"car child 1","categoryId":7,"brand":"mercedes","brandId":1,"brandModelId":6,"brandModel":"M300","cylinder":"6C","kilometer":300.0,"modelYear":"2010","fuelType":"benz","gearType":"automatic","exteriorColor":"red","interiorColor":"yellow","carType":1,"image":[],"isFavorite":false,
Here is the error I get when I click on the product to access its details:
E/flutter (13626): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: FormatException: Invalid radix-10 number (at character 1)
E/flutter (13626): id
E/flutter (13626): ^
E/flutter (13626):
E/flutter (13626): #0 int._throwFormatException (dart:core-patch/integers_patch.dart:131:5)
E/flutter (13626): #1 int._parseRadix (dart:core-patch/integers_patch.dart:142:16)
E/flutter (13626): #2 int._parse (dart:core-patch/integers_patch.dart:100:12)
E/flutter (13626): #3 int.parse (dart:core-patch/integers_patch.dart:63:12)
E/flutter (13626): #4 Cars.fetchAndSetCarDetails.<anonymous closure>
package:flutter_app/providers/car_provider.dart:88
E/flutter (13626): #5 _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:377:8)
E/flutter (13626): #6 Cars.fetchAndSetCarDetails
package:flutter_app/providers/car_provider.dart:86
E/flutter (13626): <asynchronous suspension>
E/flutter (13626): #7 _MyCarDetailsState.initState.<anonymous closure>
package:flutter_app/details/car_details.dart:23
E/flutter (13626): #8 _rootRunUnary (dart:async/zone.dart:1132:38)
E/flutter (13626): #9 _CustomZone.runUnary (dart:async/zone.dart:1029:19)
E/flutter (13626): #10 _FutureListener.handleValue (dart:async/future_impl.dart:137:18)
E/flutter (13626): #11 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:678:45)
E/flutter (13626): #12 Future._propagateToListeners (dart:async/future_impl.dart:707:32)
E/flutter (13626): #13 Future._complete (dart:async/future_impl.dart:512:7)
E/flutter (13626): #14 new Future.delayed.<anonymous closure> (dart:async/future.dart:313:16)
E/flutter (13626): #15 _rootRun (dart:async/zone.dart:1120:38)
E/flutter (13626): #16 _CustomZone.run (dart:async/zone.dart:1021:19)
E/flutter (13626): #17 _CustomZone.runGuarded (dart:async/zone.dart:923:7)
E/flutter (13626): #18 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:963:23)
E/flutter (13626): #19 _rootRun (dart:async/zone.dart:1124:13)
E/flutter (13626): #20 _CustomZone.run (dart:async/zone.dart:1021:19)
E/flutter (13626): #21 _CustomZone.bindCallback.<anonymous closure> (dart:async/zone.dart:947:23)
E/flutter (13626): #22 Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:21:15)
E/flutter (13626): #23 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:382:19)
E/flutter (13626): #24 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:416:5)
E/flutter (13626): #25 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:172:12)
E/flutter (13626):
You have several problems.
1 - your forEach closure looks like you are expecting the JSON to include a list of cars that you are going to add to loadedCars but it does not - there's just one car. That's why extractedData is a Map<String, dynamic> not a List<Map<String, dynamic>>.
2 - that means that the forEach closures is iterating over the members of the map so gets called once with carId='id' and carData=204 and then again with carId='adPrice' and carData=25.0 etc. This is clearly not what you're expecting! The exception happens when you try to parse 'id' into an int.
Given that there's only one car in your current json you can dispense with the loop. You should extract that one car like:
final response = await http.get(url);
final extractedData = json.decode(response.body) as Map<String, dynamic>;
var theOneCar = AddCar(
id: extractedData['id'], // no need for parse either - id is already an int
name: extractedData['adTitle'],
// etc
// etc
print (theOneCar);
I have this variables problem
this is my getdata function
Future <List <Deal>> getData() async{
String myUrl = "http://10.25.20.27:5000/api/all";
var response = await http.get(myUrl,
headers: {
'Accept':'application/json',
});
var jsonData = json.decode(response.body);
List<Deal> deals =[];
var u;
for( u in jsonData){
Deal deal = Deal(u["id"],u["name"],u["adress"],u["photo"],u["Description"],u["discount"]);
}
return deals;
}
And I got this error
Performing hot reload...
Reloaded 14 of 594 libraries in 902ms.
E/flutter ( 4211): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: type 'String' is not a subtype of type 'int' of 'index'
E/flutter ( 4211): #0 DatabaseHelper.getData (package:flutter_app/databasehelper.dart:116:25)
E/flutter ( 4211):
E/flutter ( 4211): #1 _HomeePageState.build. (package:flutter_app/homee_page.dart:100:80)
E/flutter ( 4211): #2 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:654:14)
E/flutter ( 4211): #3 _InkResponseState.build. (package:flutter/src/material/ink_well.dart:729:32)
E/flutter ( 4211): #4 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
E/flutter ( 4211): #5 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:365:11)
E/flutter ( 4211): #6 TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:275:7)
E/flutter ( 4211): #7 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:455:9)
I think you can create "Deal" class like below:-
class Deal {
String id;
String name;
String adress;
String photo;
String Description;
String discount;
Deal(
this.id,
this.name,
this.adress,
this.photo,
this.Description,
this.discount,
);
}
Then you can use loop like below :-
var u;
for (u in jsonData) {
Deal deal = Deal(
u["id"].toString(),
u["name"].toString(),
u["adress"].toString(),
u["photo"].toString(),
u["Description"].toString(),
u["discount"].toString());
}