必须初始化不可为 null 的变量“_database”

The non-nullable variable '_database' must be initialized

我正在使用 flutter 制作一个 Windows 应用程序,在使用 sqflite 制作数据库时,弹出此错误我不知道如何真正解决这个问题。

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]);
  }
}

这是我用于数据库助手的代码....它在 _database 中显示如下错误:

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

您的代码中存在两个问题,这两个问题均来自 Dart 2.12.0 版引入的新的默认不可空 (NNBD) 功能。这两个问题都可以在以下部分找到:

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

首先,在 Dart 2.12.0 中,Database 表示不允许 null 作为值的类型。在你的例子中,你定义了一个变量 _database ,它没有被初始化为任何值。所以这个变量的值将是 null。但是 Database 不允许这样做。

相反,我们需要使用 Database? 类型,它允许我们指向 Database 对象或 null:

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

现在我们遇到了一个新问题:

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

这样做的原因是 Dart 空安全特性在执行 if (_database == null) 时不会提升 class 字段。您可以在此处阅读更多相关信息以及原因:

要解决此问题,我们可以将您的代码重写为:

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

??= 运算符将检查 _database 是否为 null,如果是,则将其设置为 await _initiateDatabase() 的值,然后 return _database 的新值。如果 _database 已经有一个值,它将只是 returned.

可以在此处找到 Dart 中的 null 感知运算符的良好列表:https://medium.com/@thinkdigitalsoftware/null-aware-operators-in-dart-53ffb8ae80bb

您可以在此处阅读更多关于默认情况下 Dart 不可为空的信息: https://dart.dev/null-safety

奖金

我觉得你也应该改一下:

_initiateDatabase() async {

收件人:

Future<Database> _initiateDatabase() async {

由于我们不知道 _initiateDatabase return 是哪种类型,因此 Dart 会假定它是 dynamic,这不是您想要的。

也许这会对你有所帮助, 请flutter sdk修改如下

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

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]);
  }
}