The non-nullable variable '_database' must be initialized

10,010

Solution 1

There are two problems in your code which both comes from the new Dart non-nullable by default (NNBD) feature introduced with version 2.12.0. Both problems can be found in the following segment:

  static Database _database;
  Future<Database> get database async {
    if (_database == null) {
      _database = await _initiateDatabase();
    }
    return _database;
  }

First, in Dart 2.12.0, Database means a type which does not allow null as value. In your case, you define a variable _database which is not being initialized with any value. So this variable is going to have the value null. But Database does not allow that.

Instead, we need to use the type Database? which allows us to point to a Database object or null:

  static Database? _database;
  Future<Database> get database async {
    if (_database == null) {
      _database = await _initiateDatabase();
    }
    return _database;
  }

Now we get a new problem:

A value of type 'Database?' can't be returned from the function 'database' because it has a return type of 'Future<Database>'

The reason for this is Dart null-safety feature does not promote class fields when doing if (_database == null). You can read more about that here and the reason why: Dart null safety doesn't work with class fields

To fix this we can rewrite your code to:

  static Database? _database;
  Future<Database> get database async =>
      _database ??= await _initiateDatabase();

The ??= operator will check if _database is null and set it to the value of await _initiateDatabase() if that is the case and then return the new value of _database. If _database already has a value, it will just be returned.

A good list of null-aware operators in Dart can be found here: https://medium.com/@thinkdigitalsoftware/null-aware-operators-in-dart-53ffb8ae80bb

You can read more about Dart non-nullable by default here: https://dart.dev/null-safety

Bonus

I think you should also change:

_initiateDatabase() async {

To:

Future<Database> _initiateDatabase() async {

Since we do not not know which type _initiateDatabase returns and Dart will therefore assume it is dynamic which is properly not what you want.

Solution 2

Maybe this will help you, please flutter sdk change as as follows

sdk: ">=2.12.0 <3.0.0" => sdk: ">=2.7.0 <3.0.0"

Solution 3

import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';

class DatabaseHelper {
  static final dbname = "myDatabase.db";
  static final dbversion = 1;
  static final tablename = "myTable";
  static final columnId = "id";
  static final columnName = "name";

  DatabaseHelper._privateConstructor();
  static final DatabaseHelper instance = DatabaseHelper._privateConstructor();

  static Database? _database;
  Future<Database?> get database async {
    if (_database != null) {
      return _database;
    }
    _database = await initiateDatabase();
    return _database;
  }

  initiateDatabase() async {
    Directory directory = await getApplicationDocumentsDirectory();
    String path = join(directory.path, dbname);
    return await openDatabase(path, version: dbversion, onCreate: onCreate);
  }

  Future onCreate(Database db, int dbversion) async {
    return await db.execute('''
         CREATE TABLE $tablename ($columnId INTEGER PRIMARY KEY,
         $columnName TEXT NOT NULL)
      ''');
  }

  Future<int> insert(Map<String, dynamic> row) async {
    Database? db = await instance.database;
    return await db!.insert(tablename, row);
  }

  Future<List<Map<String, dynamic>>> queryAll() async {
    Database? db = await instance.database;
    return await db!.query(tablename);
  }

  Future<int> update(Map<String, dynamic> row) async {
    Database? db = await instance.database;
    int id = row[columnId];
    return await db!
        .update(tablename, row, where: '$columnId=?', whereArgs: [id]);
  }

  Future<int> delete(int id) async {
    Database? db = await instance.database;
    return await db!.delete(tablename, where: '$columnId=?', whereArgs: [id]);
  }
}
Share:
10,010
sanjay .k.santhosh
Author by

sanjay .k.santhosh

Updated on July 27, 2022

Comments

  • sanjay .k.santhosh
    sanjay .k.santhosh almost 2 years

    I am using flutter to make a Windows app and while using the sqflite and making a database, this error pops up I don't know how to really fix this.

    import 'dart:io';
    
    import 'package:path_provider/path_provider.dart';
    import 'package:path/path.dart';
    import 'package:sqflite/sqflite.dart';
    
    class DatabaseHelper {
      static final _dbName = 'Database.db';
      static final _dbVersion = 1;
      static final _tableName = 'my table';
    
      static final columnId = '_id';
      static final columnName = 'name';
    
      DatabaseHelper._privateConstuctor();
      static final DatabaseHelper instance = DatabaseHelper._privateConstuctor();
    
      static Database _database;
      Future<Database> get database async {
        if (_database == null) {
          _database = await _initiateDatabase();
        }
        return _database;
      }
    
      _initiateDatabase() async {
        Directory directory = await getApplicationDocumentsDirectory();
        String path = join(directory.path, _dbName);
        return await openDatabase(path, version: _dbVersion, onCreate: _onCreate);
      }
    
      Future _onCreate(Database db, int version) async {
        await db.execute(''' 
              CREATE TABLE $_tableName ( 
              $columnId INTEGER PRIMARY KEY,
              $columnName TEXT NOT NULL)
              
              
              ''');
      }
    
      Future<int> insert(Map<String, dynamic> row) async {
        Database db = await instance.database;
        return await db.insert(_tableName, row);
      }
    
      Future<List<Map<String, dynamic>>> queryAll() async {
        Database db = await instance.database;
        return await db.query(_tableName);
      }
    
      Future<int> update(Map<String, dynamic> row) async {
        Database db = await instance.database;
        int id = row[columnId];
        return await db
            .update(_tableName, row, where: '$columnId = ?', whereArgs: [id]);
      }
    
      Future<int> delete(int id) async {
        Database db = await instance.database;
        return await db.delete(_tableName, where: '$columnId = ?', whereArgs: [id]);
      }
    }
    

    This is the code i use for the databasehelper....it shows error in _database like this:

    The non-nullable variable '_database' must be initialized.
    Try adding an initializer expression.