(更新:如何在 sqflite 中存储 List<String> 数据类型) sqflite 错误:DatabaseException(java.lang.String 无法转换为 jav

Posted

技术标签:

【中文标题】(更新:如何在 sqflite 中存储 List<String> 数据类型) sqflite 错误:DatabaseException(java.lang.String 无法转换为 java.lang.Integer)【英文标题】:(UPDATE: How to store List<String> data type in sqflite) sqflite error: DatabaseException(java.lang.String cannot be cast to java.lang.Integer) 【发布时间】:2019-12-22 03:39:06 【问题描述】:

我有一个 sqflite 数据库,其中设置了一个表,其中除了唯一键设置为 BLOB 数据类型的所有列之外。目的是存储为二进制数据。我对飞镖和颤振很陌生,所以我尽量保持简单。我有intdoubleStringList&lt;String&gt;Map&lt;String:String&gt;DateTime 数据进入这些列。我使用的是 .insert() 函数,而不是 .rawInsert() 函数。

在我的TEST application 中,字符串或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;

这是数据库中使用的Product model。

更新:

我将生产代码模型中表示的所有数据类型添加到我的测试应用程序模型中,并且能够复制错误。请参阅顶部的测试应用程序链接。我一一删除了新的数据类型,直到错误消失,并且能够发现是 List 数据类型产生了这个错误。我仔细检查了地图,没有任何问题。

那么,提炼的问题:如何使用 sqflite 存储字符串列表?我不想只是将它存储为原始 JSON 字符串...那会很糟糕...

【问题讨论】:

【参考方案1】:

您必须展平您的模型。请参阅supported types 帮助部分。

基本上,intdoubleStringUint8List(blob) 是唯一受支持的类型。 不幸的是,您必须转换您的内部 List&lt;String&gt;Map&lt;String:String&gt;,json 是一种解决方案。

【讨论】:

谢谢!实际上我没有遇到 Map 的任何问题,但无论如何我都会将其展平以防万一。【参考方案2】:

经过一番研究,我认为我对 BLOB 的理解是不正确的——我认为这意味着它将对象存储为二进制数据,并且我还假设在 SQLite 中,如果表是 BLOB,它将强制转换所有数据插入时转换为二进制,否则至少抛出。事实证明,SQLite 并不严格,BLOB 仅表示“您想要的任何数据类型”。我还发现 SQLite 会尝试自动转换对象的数据类型。所以像 List 这样复杂的数据类型需要在存储之前转换成 SQLite 可以转换成自己的类型的东西。 SQLite 中没有 Array 或 Object 类型,所以 List 是行不通的。

我通过在插入数据库之前将复杂数据类型转换为 JSON 字符串,并在从数据库中获取/实例化对象时将其转换回列表来解决了这个问题。这样,每次我需要使用/更改该属性或其中的某些内容时,我就不必处理将对象属性转换为 JSON 的问题。不完全优雅,但它有效并且我理解它。

【讨论】:

以上是关于(更新:如何在 sqflite 中存储 List<String> 数据类型) sqflite 错误:DatabaseException(java.lang.String 无法转换为 jav的主要内容,如果未能解决你的问题,请参考以下文章

Flutter:如何使用SQFlite存储的数据?

测试 Flutter 本地 sqflite 数据库 onUpgrade 并且应用更新后没有数据显示

如何在SQFlite中插入POJO对象和列表

在 Flutter 中使用 SQFlite 将本地存储的 DB 导出为可读文件

如何在flutter中将图像数据保存到sqflite数据库以进行持久化

如何使用 StreamBuilder 更新 TextField 的值?