我有一个 sqflite 数据库,其中设置了一个表,其中除了唯一键设置为 BLOB 数据类型的所有列之外。目的是存储为二进制数据。我对飞镖和颤振很陌生,所以我尽量保持简单。我有int
, double
, String
, List<String>
,Map<String:String>
和DateTime
数据进入这些列。我使用的是 .insert() 函数,而不是 .rawInsert() 函数。
在我的TEST 应用程序中,字符串或 int 作为 BLOB 数据类型进入表中没有任何问题。我使用完全相同的代码来插入,只是具有不同列的不同对象。在我为生产而构建的应用程序中,它有更大、更长的字符串(如 base 64 中的图像)和更大的整数,我得到了错误。
奇怪的是,我有类型检查代码,它将我从服务器获取的所有整数数据转换为实际的整数数据……整数不可能是整数。每个值都通过一个只能抛出或返回整数的函数。
那么数据库将如何获取它试图转换为整数的字符串呢?
我不是在寻求解决方案,而是我应该采取的其他故障排除步骤,因为我可能会因为大脑疲劳或缺乏经验而错过。我遇到了各种各样的障碍。
这是引发异常的堆栈跟踪:
I/flutter ( 6502): #0 wrapDatabaseException (package:sqflite/src/exception_impl.dart:11:7)
I/flutter ( 6502): <asynchronous suspension>
I/flutter ( 6502): #1 SqfliteDatabaseFactoryImpl.wrapDatabaseException (package:sqflite/src/factory_impl.dart:29:7)
I/flutter ( 6502): #2 _SqfliteDatabaseBase&Object&SqfliteDatabaseMixin.safeInvokeMethod (package:sqflite/src/database_mixin.dart:183:15)
I/flutter ( 6502): #3 _SqfliteDatabaseBase&Object&SqfliteDatabaseMixin.txnRawInsert.<anonymous closure> (package:sqflite/src/database_mixin.dart:340:14)
I/flutter ( 6502): #4 _SqfliteDatabaseBase&Object&SqfliteDatabaseMixin.txnSynchronized.<anonymous closure> (package:sqflite/src/database_mixin.dart:290:22)
I/flutter ( 6502): #5 BasicLock.synchronized (package:synchronized/src/basic_lock.dart:31:26)
I/flutter ( 6502): <asynchronous suspension>
I/flutter ( 6502): #6 _SqfliteDatabaseBase&Object&SqfliteDatabaseMixin.txnSynchronized (package:sqflite/src/database_mixin.dart:286:43)
I/flutter ( 6502): <asynchronous suspension>
I/flutter ( 6502): #7 _SqfliteDatabaseBase&Object&SqfliteDatabaseMixin.txnWriteSynchronized (package:sqflite/src/database_mixin.dart:307:7)
I/flutter ( 6502): #8 _SqfliteDatabaseBase&Object&SqfliteDatabaseMixin.txnRawInsert (package:sqflite/src/database_mixin.dart:339:12)
I/flutter ( 6502): #9 _SqfliteDatabaseBase&Object&SqfliteDatabaseMixin&SqfliteDatabaseExecutorMixin.rawInsert (package:sqflite/src/database_mixin.dart:44:15)
I/flutter ( 6502): #10 _SqfliteDatabaseBase&Object&SqfliteDatabaseMixin&SqfliteDatabaseExecutorMixin.insert (package:sqflite/src/database_mixin.dart:54:12)
I/flutter ( 6502): #11 AppPersistenceManager.insertIntoDatabase (package:gogreen_utility_belt/app/AppPersistenceManager.dart:120:37)
I/flutter ( 6502): <asynchronous suspension>
I/flutter ( 6502): #12 AppNetwork._triggerProductFetchAndCacheWith.<anonymous closure> (package:gogreen_utility_belt/app/AppNetwork.dart:167:38)
I/flutter ( 6502): #13 _rootRunUnary (dart:async/zone.dart:1132:38)
I/flutter ( 6502): #14 _CustomZone.runUnary (dart:async/zone.dart:1029:19)
I/flutter ( 6502): #15 _FutureListener.handleValue (dart:async/future_impl.dart:126:18)
I/flutter ( 6502): #16 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:639:45)
I/flutter ( 6502): #17 Future._propagateToListeners (dart:async/future_impl.dart:668:32)
I/flutter ( 6502): #18 Future._chainCoreFuture (dart:async/future_impl.dart:454:7)
I/flutter ( 6502): #19 Future._complete (dart:async/future_impl.dart:466:9)
I/flutter ( 6502): #20 _SyncCompleter.complete (dart:async/future_impl.dart:51:12)
I/flutter ( 6502): #21 _AsyncAwaitCompleter.complete (dart:async-patch/async_patch.dart:28:18)
I/flutter ( 6502): #22 _completeOnAsyncReturn (dart:async-patch/async_patch.dart:294:13)
I/flutter ( 6502): #23 compute (package:flutter/src/foundation/_isolates_io.dart)
I/flutter ( 6502): <asynchronous suspension>
I/flutter ( 6502): #24 AppNetwork._triggerProductFetchAndCacheWith (package:gogreen_utility_belt/app/AppNetwork.dart:153:55)
I/flutter ( 6502): <asynchronous suspension>
I/flutter ( 6502): #25 AppNetwork.fetchAndCacheAllProducts (package:gogreen_utility_belt/app/AppNetwork.dart:195:9)
I/flutter ( 6502): #26 _asyncThenWrapperHelper.<anonymous closure> (dart:async-patch/async_patch.dart:77:64)
I/flutter ( 6502): #27 _rootRunUnary (dart:async/zone.dart:1132:38)
I/flutter ( 6502): #28 _CustomZone.runUnary (dart:async/zone.dart:1029:19)
I/flutter ( 6502): #29 _FutureListener.handleValue (dart:async/future_impl.dart:126:18)
I/flutter ( 6502): #30 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:639:45)
I/flutter ( 6502): #31 Future._propagateToListeners (dart:async/future_impl.dart:668:32)
I/flutter ( 6502): #32 Future._complete (dart:async/future_impl.dart:473:7)
I/flutter ( 6502): #33 _cancelAndValue (dart:async/stream_pipe.dart:63:12)
I/flutter ( 6502): #34 Stream.first.<anonymous closure> (dart:async/stream.dart:1190:11)
I/flutter ( 6502): #35 _rootRunUnary (dart:async/zone.dart:1132:38)
I/flutter ( 6502): #36 _CustomZone.runUnary (dart:async/zone.dart:1029:19)
I/flutter ( 6502): #37 _CustomZone.runUnaryGuarded (dart:async/zone.dart:931:7)
I/flutter ( 6502): #38 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:336:11)
I/flutter ( 6502): #39 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:263:7)
I/flutter ( 6502): #40 _SyncBroadcastStreamController._sendData (dart:async/broadcast_stream_controller.dart:375:20)
I/flutter ( 6502): #41 _BroadcastStreamController.add (dart:async/broadcast_stream_controller.dart:250:5)
I/flutter ( 6502): #42 _AsBroadcastStreamController.add (dart:async/broadcast_stream_controller.dart:474:11)
I/flutter ( 6502): #43 _rootRunUnary (dart:async/zone.dart:1136:13)
I/flutter ( 6502): #44 _CustomZone.runUnary (dart:async/zone.dart:1029:19)
I/flutter ( 6502): #45 _CustomZone.runUnaryGuarded (dart:async/zone.dart:931:7)
I/flutter ( 6502): #46 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:336:11)
I/flutter ( 6502): #47 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:263:7)
I/flutter ( 6502): #48 _SyncStreamController._sendData (dart:async/stream_controller.dart:764:19)
I/flutter ( 6502): #49 _StreamController._add (dart:async/stream_controller.dart:640:7)
I/flutter ( 6502): #50 _StreamController.add (dart:async/stream_controller.dart:586:5)
I/flutter ( 6502): #51 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:172:12)
以下是一些涉及的功能:
initDatabase() async {
print(new Trace.from(StackTrace.current).terse.frames[0]);
Directory documentsDirectory;
print(
'documentsDirectory set to null, about to assign with an await method');
documentsDirectory = await getApplicationDocumentsDirectory();
print('passed doc dir');
String path = join(documentsDirectory.path, "TestDB.db");
print('passed join');
print(Trace.from(StackTrace.current).terse);
return await openDatabase(path, version: 1, onOpen: (db) {
print('in onOpen');
}, onCreate: (Database database, int version) async {
print('in onCreate async');
for (DatabaseTable databaseTable in DatabaseTable.values) {
print(
'reached inside of "for (DatabaseTable databaseTable in DatabaseTable.values)"');
String executionString =
"CREATE TABLE IF NOT EXISTS ${RawValue.databaseTable(databaseTable)}("
"$uniqueRowKey INTEGER PRIMARY KEY,";
JSONSerializable objectExample;
switch (databaseTable) {
case DatabaseTable.Product:
objectExample = Product.example;
}
print('getting parameters');
List<String> parameters = [];
for (String key
in getDatabaseKeyedMapFrom(serialObject: objectExample).keys) {
parameters.add(key);
}
print('getting unique keys');
List<String> uniqueKeys = [];
var rawUniqueProperties = objectExample.uniqueProperties();
for (String property in rawUniqueProperties) {
uniqueKeys.add(getDatabaseKeyFrom(jsonKey: property));
}
print('iterating through parameters');
for (String parameter in parameters) {
if (parameter != parameters.first) {
executionString += ',';
}
if (uniqueKeys.contains(parameter)) {
uniqueKeys.remove(parameter);
executionString += "$parameter BLOB UNIQUE";
continue;
}
executionString += "$parameter BLOB";
}
executionString += ')';
print('executing string on database');
await database.execute(executionString);
}
});
}
/// Attempts to insert the object into its corresponding table.
Future<DatabaseLocation> insertIntoDatabase(JSONSerializable object) async {
print(new Trace.from(StackTrace.current).terse.frames[0]);
final localDatabase = await database;
String tableName = RawValue.databaseTable(getTableFor(object));
try {
Map<String, dynamic> dbKeyedMap =
getDatabaseKeyedMapFrom(serialObject: object);
int row = await localDatabase.insert(tableName, dbKeyedMap,
conflictAlgorithm: ConflictAlgorithm.replace);
return DatabaseLocation(table: tableName, row: row);
} catch (error, trace) {
printWrapped(error.toString());
printWrapped(trace.toString());
rethrow;
}
}
///converts the String keys of any map representing an object into snake_case
Map<String, dynamic> getDatabaseKeyedMapFrom(
{JSONSerializable serialObject}) {
print(new Trace.from(StackTrace.current).terse.frames[0]);
Map<String, dynamic> jsonKeyedMap = serialObject.toJson();
List<String> jsonPropertyNames = serialObject.propertyNames();
Map<String, dynamic> databaseKeyedMap = {};
for (String jsonPropertyName in jsonPropertyNames) {
ReCase reCase = ReCase(jsonPropertyName);
String databasePropertyName = reCase.snakeCase;
databaseKeyedMap[databasePropertyName] = jsonKeyedMap[jsonPropertyName];
}
return databaseKeyedMap;
}
///converts the String keys of any map representing an object into camelCase
Map<String, dynamic> getJSONKeyedMapFrom(
{Map<String, dynamic> databaseKeyedMap}) {
////print(new Trace.from(StackTrace.current).terse.frames[0]);
List<String> databasePropertyNames = databaseKeyedMap.keys;
Map<String, dynamic> jsonKeyedMap = {};
for (String databasePropertyName in databasePropertyNames) {
ReCase reCase = ReCase(databasePropertyName);
String jsonPropertyName = reCase.camelCase;
jsonKeyedMap[jsonPropertyName] = databaseKeyedMap[databasePropertyName];
}
return jsonKeyedMap;
}
这是数据库中使用的产品模型。
更新:
我将生产代码模型中表示的所有数据类型添加到我的测试应用程序模型中,并且能够复制错误。请参阅顶部的测试应用程序链接。我一一删除了新的数据类型,直到错误消失,并且能够发现是 List 数据类型产生了这个错误。我仔细检查了地图,这不会造成任何麻烦。
所以,精致的问题:如何使用 sqflite 存储字符串列表?我不想把它存储为原始的 JSON 字符串......那会很糟糕......