I received - Null check operator used on a null value this error while trying to test my sqflite application. Even thought the code is working in emulator. but it didnt passed the test.
Kindly help.
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
class DbHelper {
static final DbHelper instance = DbHelper._instance();
DbHelper._instance();
static Database? _db;
Future<Database> get db async {
if (_db != null) return db;
_db = await _initDb();
return _db!;
}
Future<Database> _initDb() async {
Directory dir = await getApplicationDocumentsDirectory();
String path = dir.path + '/account_keeper.db';
final accountManagerDb = await openDatabase(
path,
version: 1,
onCreate: _createDb,
);
return accountManagerDb;
}
void _createDb(Database db, int version) async {
// Table 1- BusinessProfile Profile
print('creating db');
print('--create database--');
const String businessProfileTable = 'businessProfile_table';
String businessId = 'id';
String businessName = 'businessName';
await db.execute(
'''
CREATE TABLE
$businessProfileTable(
$businessId INTEGER PRIMARY KEY AUTOINCREMENT,
$businessName TEXTT )''',
);
}
}
Related
I'm a beginner in flutter, i want to use SQlite database using sqflite package in my Flutter App,
i have an error when i call the method insertAnnonce saying :
Error: MissingPluginException(No implementation found for method getApplicationDocumentsDirectory on channel plugins.flutter.io/path_provider)
import "dart:io" as io;
import 'dart:io';
import "package:path/path.dart";
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
import 'annonce.model.dart';
class AppData {
static const _dbVersion = 1;
AppData._();
static final AppData instance = AppData._();
static Database? _database;
Future<Database?> get database async {
print("Get database");
print(_database);
print("Get database");
if (_database != null) {
return _database;
}
_database = await _initializeDatabase();
print("initializeDatabase");
print(_database);
print("initializeDatabase");
return _database;
}
Future<Database> _initializeDatabase() async {
print("initializeDatabase");
Directory directory = await getApplicationDocumentsDirectory();
String path = join(directory.path, 'annonce_database.db');
return await openDatabase(path, version: _dbVersion, onCreate: _onCreate);
}
Future _onCreate(Database db, int version) async {
print("_onCreate");
try {
const createQuery = '''
CREATE TABLE `annonce` (`id` INT NOT NULL , `titre` VARCHAR(250) NOT NULL , `prix` INT NOT NULL , `description` TEXT NOT NULL , `idAnnonceur` INT NOT NULL , `active` INT NOT NULL , `isFavorite` INT NOT NULL , `favoriteCount` INT NOT NULL , PRIMARY KEY (`id`));
''';
await db.execute(createQuery);
} catch (e) {}
}
void insertAnnonce(Annonce annonce) async {
final Database db = await database as Database;
print('insertAnnonce');
print(db);
print('insertAnnonce');
await db.insert(
'annonce',
annonce.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
}
My team and I are currently in the process of trying to port an older Android project over to Flutter and are having issues with the Dart null checker in our DatabaseService class.
Using a number of resources we found on Google, the class currently is defined as:
import 'dart:async';
import 'package:logging/logging.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:agineek/models/player.dart';
class DatabaseService {
static const _dbName = 'agineek.db';
static final DatabaseService _instance = DatabaseService._internal();
static Database _db;
factory DatabaseService() => _instance;
final Logger log = Logger('Database');
DatabaseService._internal();
Future<Database?> get db async {
if(_db != null) {
return _db;
}
// ignore: join_return_with_assignment
_db = await _openDatabase();
return _db;
}
/// Open a connection to the [Database] and perform
/// database creation transactions.
Future<Database> _openDatabase() async {
final dbPath = await getDatabasesPath();
final database = await openDatabase(
join(dbPath, _dbName),
version: 1,
onCreate: (Database db, int version) async {
await db.execute('''
create table ${Player.tableName} (
${Player.columnPlayerId} integer primary key autoincrement,
${Player.columnPlayerHitColor} text not null
);
''');
}
);
return database;
}
/// Create a [Player] entry in the database.
/// Conflicts are resolved as a replace action.
Future<Player> createPlayer(Player player) async {
final database = _db;
player.id = await database.insert(
Player.tableName,
player.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace
);
return player;
}
... a bunch of other boilerplate transactions
}
However, we're stuck with trying to figure out why the static _db is being flagged as a dart(not_initialized_non_nullable_variable) error.
Any assistance would be appreciated.
Try adding the late keyword as such:
static late Database _db;
But that would require some extra changes I guess. So an alternative would be to make it nullable:
static Database? _db;
I keep getting this syntax error : E/SQLiteLog( 4514): (1) near "null": syntax error in "CREATE TABLE expenses_table(id INTEGER PRIMARY KEY AUTOINCREMENT, null TEXT ,null TEXT)"
I am quite new to this, and have been using examples online to put this code together, but I can't seem to find what is causing this issue.
Any help would be very much appreciated!
'''
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'dart:async';
import 'expense_list.dart';
class ExpensesDatabase {
static ExpensesDatabase _expensesDatabase;
static Database _database;
String expensesTable = 'expenses_table';
String id = 'id';
String name;
String amount;
ExpensesDatabase._createInstance();
factory ExpensesDatabase() {
if (_expensesDatabase == null) {
_expensesDatabase = ExpensesDatabase._createInstance();
}
return _expensesDatabase;
}
Future<Database> get database async {
if (_database == null) {
_database = await initializeDatabase();
}
return _database;
}
Future<Database> initializeDatabase() async {
Directory directory = await getApplicationDocumentsDirectory();
String path = directory.path + 'expenses.db';
var expensesDatabase =
await openDatabase(path, version: 1, onCreate: _createDb);
return expensesDatabase;
}
void _createDb(Database db, int newVersion) async {
await db.execute(
'CREATE TABLE $expensesTable($id INTEGER PRIMARY KEY AUTOINCREMENT,'
'$name TEXT,'
'$amount TEXT)');
}
'''
Intialize your name and amount variables, its getting null because string name and amount are not initialised yet.
String name = 'name';
String amount = 'amount';
I am trying to get an async function _read() to run and the function does not pass the line:
Reading reading = await helper.queryReading(rowId); in this function:
_read() async {
DatabaseHelper helper = DatabaseHelper.instance;
int rowId = 1;
//lines above here executes
Reading reading = await helper.queryReading(rowId); //this is the line it stops on
// nothing below here is executed
if (reading == null) {
print('read row $rowId: empty');
} else {
print('read row $rowId: ${reading.reading}');
}
}
It is being called from the following function
class Profile {
Widget getScreen(){
print("Attempting to read db");
_read();
return Scaffold( ...)
Here is my helper class:
import 'dart:ffi';
import 'dart:io';
import 'package:ema/Readings.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
//table structure
final String tableName = 'Readings';
final String databasecolumnId = '_id';
final String databaseReading = 'Reading';
final String databaseDate = 'Time';
class DatabaseHelper {
//This is the name of the database file on disk
static final _databaseName = "readings.db";
//handles versioning for databases
static final _databaseVersion = 1;
//makes a singleton classs
DatabaseHelper._privateConstructor();
static final DatabaseHelper instance = DatabaseHelper._privateConstructor();
//allows only one item to access the database
static Database _database;
Future<Database> get database async {
_database = await _initDatabase();
return database;
}
//this opens and creates the database
_initDatabase() async {
// The path_provider plugin gets the right directory for Android or iOS.
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, _databaseName);
// Open the database. Can also add an onUpdate callback parameter.
return await openDatabase(path,
version: _databaseVersion,
onCreate: _onCreate);
}
//Creates the database
Future _onCreate(Database db, int version) async {
await db.execute(
'''
CREATE TABLE $tableName (
$databasecolumnId INTEGER PRIMARY KEY,
$databaseReading REAL NOT NULL,
$databaseDate INTERGER NOT NULL
)
'''
);
}
Future<int> insertReading(Reading reading) async {
Database db = await database;
int id = await db.insert(tableName, reading.toMap());
return id;
}
//gets reading
Future<Reading> queryReading(int id) async {
print("queryReading"); //gets here
Database db = await database;
print("Getting Db"); // not actually getting here
List<Map> maps = await db.query(tableName,
columns: [databasecolumnId, databaseReading, databaseDate],
where: '$databasecolumnId = ?',
whereArgs: [id]);
if (maps.length > 0) {
return Reading.fromMap(maps.first);
}
print('maps length : ${maps.length}');
return null;
}
}
Here is my Readings class:
class Reading {
int id;
double reading;
DateTime date;
//constructor
Reading({this.id, this.reading, this.date});
Map<String, dynamic> toMap() {
var map = <String, dynamic>{
databaseReading: reading,
databaseDate: date.millisecondsSinceEpoch,
};
if (id != null) {
map[databasecolumnId] = id;
}
return map;
}
//extracts a node object from the map obect
Reading.fromMap(Map<String, dynamic> map) {
id = map[databasecolumnId];
reading = map[databaseReading];
date = new DateTime.fromMillisecondsSinceEpoch(map [databaseDate]);
}
}
Turns out there was a deadlock in getting the database. By putting a lock on it it worked.
Here is the code to resolve it:
///declreation of the database
Database _database;
///Gets the database ensuring that there are no locks currently on the database
Future<Database> get database async {
if (_database != null) return _database;
_database = await _initDatabase();
return _database;
}
I'm learning Flutter and am on to my second program. This program uses SQFlite, and I copied most of the db handling from another program which appears to use a common pattern. I have made some modifications to it.
What I don't like, is having to evaluate the db every time to determine if it needs to be created as in "Database db = await this.db;". I would prefer it if it was simply created when the class is created, and then just used as instantiated. However, I'm unfamiliar with "._internal", and unfamiliar with "factory", so I'm unsure of the best way to achieve that aim.
Would appreciate if someone could show me how to best achieve that. IE. Remove the need for "Database db = await this.db;", and just reference the db.
Extract of relevant code for DbHelper is as follows:
import 'package:sqflite/sqflite.dart';
import 'dart:async';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'noteRec.dart';
class DbHelper {
static final DbHelper _dbHelper = DbHelper._internal();
static const String sTblNotes = "Notes";
static const String sColId = "Id";
static const String sColTitle = "Title";
static const String sColDetail = "Detail";
DbHelper._internal();
factory DbHelper() {
return _dbHelper;
}
static Database _db;
Future<Database> get db async {
return _db != null ? _db : await initializeDb();
}
Future<Database> initializeDb() async {
Directory dir = await getApplicationDocumentsDirectory();
String path = dir.path + "/Notes.db";
_db = await openDatabase(path, version: 1, onCreate: _createDb);
return _db;
}
void _createDb(Database db, int newVersion) async {
await db.execute(
"CREATE TABLE $sTblNotes($sColId INTEGER PRIMARY KEY, $sColTitle TEXT, " +
"$sColDetail TEXT)");
}
Future<List> getNoteRecs() async {
Database db = await this.db;
var result =
await db.rawQuery("SELECT * FROM $sTblNotes ORDER BY $sColTitle ASC");
return result;
}
The following appears to do what I want to achieve.
dbHelper.dart
import 'dart:async';
import 'dart:io';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
import 'noteRec.dart';
class DbHelper {
static final DbHelper _dbHelper = DbHelper._internal();
static const String sTblNotes = "Notes";
static const String sColId = "id";
static const String sColTitle = "title";
static const String sColDetail = "detail";
static Database _db;
DbHelper._internal();
factory DbHelper() {
return _dbHelper;
}
Future<bool> openDb() async {
if (_db == null) {
Directory dir = await getApplicationDocumentsDirectory();
_db = await openDatabase("${dir.path}/Notes.db",
version: 1, onCreate: _createDb);
}
return (_db != null);
}
void _createDb(Database db, int newVersion) async {
await db.execute(
"CREATE TABLE $sTblNotes($sColId INTEGER PRIMARY KEY, $sColTitle TEXT, " +
"$sColDetail TEXT)");
}
Future<List> getNoteRecs() async {
return await _db
.rawQuery("SELECT * FROM $sTblNotes ORDER BY $sColTitle ASC");
}
main.dart
import 'package:flutter/material.dart';
import 'dbHelper.dart';
import 'NotesList.dart';
DbHelper _dbHelper = DbHelper();
void main() async {
await _dbHelper.openDb();
runApp(MaterialApp(home: NotesList()));
}