how to use SQlite database using sqflite package in flutter - flutter

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

Related

Creating a DatabaseService in Dart/Flutter

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;

Non-nullable instance field must be initialized and Unhandled error LateInitializationError

I'm trying to create a database and store an API token for user login but I keep getting an error when the app builds/compiles:
Non-nullable instance field '_database' must be initialized
I've tried adding a late modifier as suggested which then throws:
E/flutter ( 6894): [ERROR:flutter/lib/ui/ui_dart_state.cc(199)]
Unhandled Exception: Unhandled error LateInitializationError: Field
'_database#637109567' has not been initialized. occurred in Instance
of 'AuthenticationBloc'.
my user_db.dart
import 'dart:io';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
final userTable = 'userTable';
class DatabaseProvider {
static final DatabaseProvider dbProvider = DatabaseProvider();
//non nullable error on _database
Database _database;
Future <Database> get database async {
print('before condition');
if (_database != null){
return _database;
}
_database = await createDatabase();
return _database;
}
createDatabase() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, "User.db");
var database = await openDatabase(
path,
version: 1,
onCreate: initDB,
onUpgrade: onUpgrade,
);
return database;
}
void onUpgrade(
Database database,
int oldVersion,
int newVersion,
){
if (newVersion > oldVersion){}
}
void initDB(Database database, int version) async {
await database.execute(
"CREATE TABLE $userTable ("
"id INTEGER PRIMARY KEY, "
"username TEXT, "
"token TEXT "
")"
);
}
}
my AuthBloc.dart
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:meta/meta.dart';
import 'package:equatable/equatable.dart';
import 'package:times/repository/user_repository.dart';
import 'package:times/model/user_model.dart';
part 'authentication_event.dart';
part 'authentication_state.dart';
class AuthenticationBloc
extends Bloc<AuthenticationEvent, AuthenticationState> {
AuthenticationBloc({required this.userRepository})
: super(AuthenticationUnauthenticated())
;
final UserRepository userRepository;
#override
Stream<AuthenticationState> mapEventToState(
AuthenticationEvent event,
) async* {
if (event is AppStarted) {
final bool hasToken = await userRepository.hasToken();
if (hasToken) {
yield AuthenticationAuthenticated();
} else {
yield AuthenticationUnauthenticated();
}
}
if (event is LoggedIn) {
yield AuthenticationLoading();
await userRepository.persistToken(
user: event.user
);
yield AuthenticationAuthenticated();
}
if (event is LoggedOut) {
yield AuthenticationLoading();
await userRepository.deleteToken(id: 0);
yield AuthenticationUnauthenticated();
}
}
}
The problem is being caused by this line
if (_database != null) {
You can't directly apply null check on a non-nullable variable and since it is a late variable and you didn't initialize it, the null check will always keep throwing the error.
One way to fix this would be to make your _database Nullable and instantiate it to null, like this
Database? _database = null;
In order to avoid using the Nullable type everywhere in code, you could modify your function to use the bang operator (!) like this,
Future <Database> get database async {
if (_database != null){
return _database!;
}
_database = await createDatabase();
return _database!;
}

Sqlflite - Null check operator used on a null value

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 )''',
);
}
}

Flutter does not run Async function

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

flutter sqflite db assets

I want to access database from assets and I'm getting this error
NoSuchMethodError (NoSuchMethodError: The method 'rawQuery' was called on null.
Receiver: null
Tried calling: rawQuery("SELECT * FROM productss"))
import 'dart:io';
import 'package:path/path.dart';
import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:sqflite/sqflite.dart';
class DatabaseHelper2{
static final DatabaseHelper2 _instance = DatabaseHelper2.internal();
factory DatabaseHelper2() =>_instance;
var oneSecond = Duration(seconds: 5);
static Database _db;
Future<Database> get db async{
if(_db != null){
print("database does");
return _db;
}
_db = await initDbs();
print("database doesnt");
return _db;
}
DatabaseHelper2.internal();
initDbs() async{
// Construct a file path to copy database to
var databasesPath = await getDatabasesPath();
var path = join(databasesPath, "productss.db");
// Check if the database exists
var exists = await databaseExists(path);
if (!exists) {
// Should happen only the first time you launch your application
print("Creating new copy from asset");
// Make sure the parent directory exists
try {
await Directory(dirname(path)).create(recursive: true);
} catch (_) {}
// Copy from asset
ByteData data = await rootBundle.load(join("assets", "productss.db"));
List<int> bytes =
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
// Write and flush the bytes written
await File(path).writeAsBytes(bytes, flush: true);
} else {
print("Opening existing database");
}
// open the database
_db = await openDatabase(path);
}
void productDb2(Database database, int version)async{
await database.execute("""
CREATE TABLE productss
(
id INTEGER PRIMARY KEY,
name TEXT,
price INTEGER,
size INTEGER,
fat100 INTEGER,
carbs100 INTEGER,
protein100 INTEGER,
dateCreated String
)
""");
}
Future<List> getProductsdb()async{
var dbClient = await db;
var result = await dbClient.rawQuery("SELECT * FROM productss");
return result.toList();
}
}
I have no idea why this is happening.
Database isn't null. I checked.
You're trying to await db, but the class property is named _db. Did the IDE not catch this error?