Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The non-nullable variable '_database' must be initialized

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.
like image 538
sanjay .k.santhosh Avatar asked Apr 11 '21 19:04

sanjay .k.santhosh


People also ask

What is non-nullable variable?

Nullable variables may either contain a valid value or they may not — in the latter case they are considered to be nil . Non-nullable variables must always contain a value and cannot be nil . In Oxygene (as in C# and Java), the default nullability of a variable is determined by its type.

How do you assign a null value in DART?

With null safety, all the runtime null-dereference errors will now be shown in compile time. String name = null ; // This means the variable name has a null value. Example : Dart.


Video Answer


3 Answers

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.

like image 56
julemand101 Avatar answered Oct 18 '22 00:10

julemand101


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"

like image 29
方世玉 Avatar answered Oct 18 '22 00:10

方世玉


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]);
  }
}
like image 22
Nitesh Setti Avatar answered Oct 18 '22 02:10

Nitesh Setti