skip to Main Content

The following is the outline of a function in a Flutter application which retrieves from a database and maps the result set to objects:

class SQLHelper {
  static Future<List<MyObject>> retrieve(int moduleId) async {
    final db = await openDatabaseFromAssets('myTable.db');

    final List<Map<String, dynamic>> maps = await db
        .rawQuery('SELECT * FROM mytable WHERE moduleid = ?', [moduleId]);

    return List.generate(maps.length, (i) {
      return const MyObject(
          // pass result set to MyObject constructor
       );
    });
  }
}

Future<Database> openDatabaseFromAssets(String dbName) async {
  // Get the temporary directory (cache)
  final directory = await getTemporaryDirectory();

  final path = join(directory.path, dbName);

  // Check if the database file exists
  final exists = await File(path).exists();

  if (!exists) {
    // Copy from assets
    ByteData data = await rootBundle.load('assets/db/$dbName');
    List<int> bytes =
        data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);

    // Write and flush the bytes written
    await File(path).writeAsBytes(bytes, flush: true);
  }

  // Open the database
  return await openDatabase(path);
}

When debugging, the openDatabaseFromAssets method is called as expected, but after the following line:

directory = await getTemporaryDirectory();

the debugger stops after the line which calls the retrieve method. As no data is yet retrieved, there is a null error. Then, the application continues in the openDatabaseFromAssets function, on the line after the call to getTemporaryDirectory.

The retrieve method is called as follows:

  List<Sentence> getMyObjects(int moduleId) {
    List<MyObject>? sss;
    Future<List<MyObject>> s = SQLHelper.retrieve(moduleId);
    s.then((value) => sss = value);
    return sss!;
  }

getTemporaryDirectory is defined in path_provider.dart.

In pubspec.yaml, db path is declared as follows:

  assets:
    - assets/db/

What could account for this?

Thanks

2

Answers


  1. The problem might be with the use of const in the List.generate method, as you cannot use const with asynchronous operations.

    Here’s the corrected code:

    class SQLHelper {
      static Future<List<MyObject>> retrieve(int moduleId) async {
        late Database db;
        db = await openDatabaseFromAssets('myDB.db');
    
        final List<Map<String, dynamic>> maps = await db.rawQuery('SELECT * FROM mytable WHERE moduleid = ?', [moduleId]);
    
        return List.generate(maps.length, (i) {
          return MyObject(
            // pass result set to MyObject constructor
            
          );
        });
      }
    }
    
    Future<Database> openDatabaseFromAssets(String dbName) async {
      // open the database and return it
    }
    
    Login or Signup to reply.
  2. I think there is an issue in the query retrieving list type in the retrieve function. Try with dynamic map list type, like below:

    static Future<List<MyObject>> retrieve(int moduleId) async {
        Database? db;
        db = await openDatabaseFromAssets('myDB.db');
        if(db == null) {
         print("error in db opening");
         return [];
        }
        else {
         final List<Map> maps = await db
            .rawQuery('SELECT * FROM mytable WHERE moduleid = ?', [moduleId]);
    
         return List.generate(maps.length, (i) {
          return const MyObject(
              // pass result set to MyObject constructor
           );
         });
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search