The non-nullable variable '_database' must be initialized
Asked Answered
R

4

13

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.
Russell answered 11/4, 2021 at 19:5 Comment(3)
Your variable static Database _database; is not assigned any value when initialized. So the value are going to be null. But because you are using Dart 2.12, the type Database is a non-nullable type so it can never be null. If you want to allow it to have the value null, you should change the type to Database? which allows the variable to point to a Database object or null.Rathbone
thankyou it worked but now it is showing "A value of type 'Database?' can't be returned from the function 'database' because it has a return type of 'Future<Database>'".Russell
Does this answer your question? Non-nullable instance field must be initializedHerbal
R
64

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.

Rathbone answered 12/4, 2021 at 5:57 Comment(2)
Regarding your bonus point, adding Future<Database> before the method cause an error prompting to add a return clause. But adding "return _database;" will cause an error too: A value of type "Database?" can't be returned from the method '_initiateDatabase' because it has a return type of 'Future<Database>'.Latifundium
@Latifundium You need to read the code from the question. The _initiateDatabase() function is not suppose to return _database. Please also read about null-safety in Dart since you seem to get confused about that.Rathbone
B
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]);
  }
}
Backsaw answered 22/7, 2021 at 16:28 Comment(1)
Please edit your answer and explain what this code does, for more clarification. Read How to Answer and take the tour to learn how this site works.Macario
T
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"

Tidbit answered 10/6, 2021 at 13:5 Comment(1)
this is not the right way to proceed.Superstructure
L
1

In my opinion, the best solution is to do the following, as it checks the _database variable is not null before it is used:

  static Database? _database;
  Future<Database?> get database async {
  if (_database != null) return _database;
  _database = await _databaseConnection.setDatabase();
  return _database;
  } 
Lyonnesse answered 4/9, 2022 at 19:53 Comment(1)
While this code may solve the question, including an explanation of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please edit your answer to add explanations and give an indication of what limitations and assumptions apply.Ovid

© 2022 - 2025 — McMap. All rights reserved.