Flutter (dart) Delete by Sqflite - flutter

I need help :(
I'm trying to delete Data from a Sqflite Database.
I can insert and get the data to show, but I cannot delete it if I do a mistake in saving it.
I have my DB:
import 'package:sqflite/sqflite.dart' as sql;
import 'package:path/path.dart' as path;
import 'package:sqflite/sqflite.dart';
//SQFLITE
class DBHelper {
static Future<sql.Database> database() async {
final dbPath = await sql.getDatabasesPath();
//einmal die Datenbank erstellen in einer Variablen
return sql.openDatabase(path.join(dbPath, 'wanderwege.db'),
onCreate: (db, version) {
return db.execute(
'CREATE TABLE user_places(id TEXT PRIMARY KEY, title TEXT, image TEXT, createTime TEXT, place TEXT, description TEXT)');
// 'CREATE TABLE user_places(id TEXT PRIMARY KEY, title TEXT, image TEXT, loc_lat REAL, loc_lng REAL, address TEXT)');
}, version: 1);
}
//Da der Eintrag dauern kann bis es in die Daten gespeichert weerden = Future + async
static Future<void> insert(String table, Map<String, Object> data) async {
final db = await DBHelper.database();
db.insert(table, data, conflictAlgorithm: sql.ConflictAlgorithm.replace);
}
// Delete data from table
// deleteData(table, itemId) async {
// final db = await DBHelper.database();
// return await db.rawDelete("DELETE FROM $table WHERE id = $itemId");
// }
//Methode um Einträge zu holen
static Future<List<Map<String, dynamic>>> getData(String table) async {
final db = await DBHelper.database();
return db.query(table);
}
}
Then I have my Places:
import 'dart:io';
import 'package:flutter/widgets.dart';
import 'package:places/helpers/db_helper.dart';
import 'package:places/models/place.dart';
import 'package:intl/intl.dart';
class GreatPlaces with ChangeNotifier {
//To set Creation Time
static DateTime actualTime = DateTime.now();
String formattedDate = DateFormat('dd-MM-yyyy').format(actualTime);
List<Place> _items = [];
List<Place> get items {
return [..._items];
}
//Information des gesamten places
Place findById(String id) {
return items.firstWhere((place) => place.id == id);
}
Future<void> addPlace(
String pickedTitle,
File pickedImage,
String pickedDate,
String pickedLocation,
String pickedDescription,
//PlaceLocation pickedLocation,
) async {
//final address = await LocationHelper.getPlaceAddress(
// pickedLocation.latitude, pickedLocation.longitude);
// final updatedLocation = PlaceLocation(
// latitude: pickedLocation.latitude,
// longitude: pickedLocation.longitude,
// address: address);
final newPlace = Place(
id: DateTime.now().toString(),
image: pickedImage,
title: pickedTitle,
createTime: pickedDate,
place: pickedLocation,
description: pickedDescription,
);
//location: null);
_items.add(newPlace);
notifyListeners();
//übergabe 'wanderwege' so wie in db_helper definiert , Data ist von typ map
DBHelper.insert('user_places', {
'id': newPlace.id,
'title': newPlace.title,
'image': newPlace.image.path,
'createTime': newPlace.createTime,
'place': newPlace.place,
'description': newPlace.description
// 'loc_lat': newPlace.location.latitude,
// 'loc_lng': newPlace.location.longitude,
// 'address': newPlace.location.address,
});
}
//Die ganzen places aus der DB holen
Future<void> fetchAndSetPlaces() async {
final dataList = await DBHelper.getData('user_places');
_items = dataList
.map((item) => Place(
id: item['id'],
title: item['title'],
image: File(item['image']),
createTime: item['createTime'],
place: item['place'],
description: item['description'],
//location: null // latitude: item['loc_lat'],
// longitude: item['loc_lat'],
// address: item['address']),
))
.toList();
notifyListeners();
}
}
and now on the screen where all the Places listed I want to implement a delete function, but I don't get how it works... tried so much from youtube and the documentation from Sqflite, but I don't get it.
I hope someone can help me.
Greetings :)

I've made this simple helper file (like you have done) for a little app that uses sqflite as backend in local. It's complete: it accesses to the local file system to get grant permissions, it opens the file for write , and you can make also Batch updates:
import 'dart:async';
import 'package:sqflite/sqflite.dart';
class DBClient {
final logger = Log.getLogger('\u{1F5AB} DBClient '); // a little logger utility, you can substitute with the simple 'print(...)' function.
static final String dbFilename = 'my_database.db';
final Permission permission;
Database _database;
bool openingDB = false;
DBClient(this.permission) : assert(permission != null);
Batch batch() {
return _database.batch();
}
Future<void> init() async {
if (_database == null && !openingDB) {
String path;
try {
path = await permission.getAbsoluteFileName(dbFilename);
} on Error {
logger.e('Error: cannot open db');
rethrow;
}
openingDB = true;
logger.d('Opening database on path: $path');
_database = await openDatabase(path, version: 1,
onCreate: (Database db, int version) async {
await db.execute("""
CREATE TABLE IF NOT EXISTS ......
""");
await db.execute("""
CREATE TABLE IF NOT EXISTS ....
""");
....
await db.execute("""
CREATE TABLE IF NOT EXISTS ....
""");
});
}
}
Future<int> insert(String tableName, Map<String, dynamic> json) async =>
_database.insert(tableName, json);
Future<List<Map<String, dynamic>>> query(
String tableName, {
String where,
List<dynamic> whereArgs,
}) async {
return _database.query(
tableName,
where: where,
whereArgs: whereArgs,
);
}
Future<int> update(String tableName, Map<String, dynamic> json,
{String where, List<dynamic> whereArgs}) async {
return _database.update(
tableName,
json,
where: where,
whereArgs: whereArgs,
);
}
Future<int> delete(String tableName,
{String where, List<dynamic> whereArgs}) async {
return _database.delete(
tableName,
where: where,
whereArgs: whereArgs,
);
}
}
You can use in this manner:
deleted = await db.delete(Place.tableName(),
where: "name = ?", whereArgs: [name]);
Hint: in the init() method you can use AsyncMemoizer class, it is better to grant that the method is called only once (at the time I wrote the app I didn't do it....)
Hereafter my (very old) dependencies:
dependencies:
date_utils: ^0.1.0+3
equatable: ^1.1.1
logger: ^0.8.3
permission_handler: ^5.0.0+hotfix.3
quiver: ^2.1.3
sqflite: ^1.3.0
path_provider: ^1.6.5
flutter:
sdk: flutter

String q = "DELETE FROM Test WHERE id= '$id'";

Just use this:
await db.rawDelete('DELETE FROM $table WHERE id = ?',[itemId],);

Just use this function with parameter as id
Future<int> delete(int id) async {
return await db.delete(tableName, where: '$columnId = ?', whereArgs: [id]);}

Related

How to make sqflite database faster?

I am trying to developing an app. In this app I need a local database. I choose sqflite database but it is very slow. It is taking so much time to fetch and insert data. It is my database helper class. As you can see in code that I have lot of rows. I am new at asking question if you need more information you can comment.
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart' as sqf;
class DataBaseHelper {
static Future<sqf.Database> database() async {
final dbPath = sqf.getDatabasesPath();
return sqf.openDatabase(
join(await dbPath, 'habits_record.db'),
onCreate: (db, version) async {
await db.transaction((txn) async {
var batch = txn.batch();
await txn.execute(
'''CREATE TABLE habitTable(id INTEGER PRIMARY KEY, title TEXT, reason TEXT,plan TEXT, iconData TEXT,hour INTEGER, minute INTEGER, notificationText TEXT, notificationId INTEGER,alarmHour INTEGER, alarmMinute INTEGER)''',
);
await txn.execute(
'''CREATE TABLE event(id TEXT PRIMARY KEY, dateTime TEXT, habitId INTEGER)''',
);
await txn.execute(
'''CREATE TABLE note(id TEXT PRIMARY KEY, dateTime TEXT, habitId INTEGER, Note TEXT)''',
);
await batch.commit();
});
},
version: 1,
);
}
static Future<void> insertNote(Map<String, Object> data) async {
final db = await DataBaseHelper.database();
db.insert('note', data, conflictAlgorithm: sqf.ConflictAlgorithm.replace);
}
static Future<void> deleteNote(String id) async {
final db = await DataBaseHelper.database();
await db.delete(
'note',
where: 'id = ?',
whereArgs: [id],
);
}
static Future<List<Map<String, dynamic>>> fetchAndSetNotes() async {
final db = await DataBaseHelper.database();
return await db.query('note');
}
static Future<void> updateNote(Map<String, Object> newNote) async {
final db = await DataBaseHelper.database();
final batch = db.batch();
batch.update(
'note', newNote, where: 'id = ?',
whereArgs: [newNote['id']],
);
batch.commit(continueOnError: true);
}
static Future<void> insertEvent(Map<String, Object> data) async {
final db = await database();
await db.insert('event', data,
conflictAlgorithm: sqf.ConflictAlgorithm.replace);
}
static Future<void> deleteEvent(String id) async {
final db = await DataBaseHelper.database();
await db.delete(
'event',
where: 'id = ?',
whereArgs: [id],
);
}
static Future<List<Map<String, dynamic>>> fethEvent() async {
final db = await DataBaseHelper.database();
return await db.query('event');
}
static Future<void> insertHabit(Map<String, Object> data) async {
final db = await database();
await db.insert('habitTable', data,
conflictAlgorithm: sqf.ConflictAlgorithm.replace);
}
static Future<List<Map<String, dynamic>>> habits() async {
final db = await DataBaseHelper.database();
return await db.query('habitTable');
}
static Future<void> deleteHabit(int id) async {
final db = await DataBaseHelper.database();
await db.delete(
'habitTable',
where: 'id = ?',
whereArgs: [id],
);
}
static Future<void> updateHabit(Map<String, Object> oneHabit) async {
final db = await DataBaseHelper.database();
await db.update(
'habitTable',
oneHabit,
where: 'id = ?',
whereArgs: [oneHabit['id']],
);
}
}
Here is the ObjectBox vs Hive vs
Sqflite performance benchmarks.
You can decide which one you want to go with.
In CRUD operations, you can see that sqflite is very slow when comparing with others.
If sqflite has not the speed you want , you can use hive or objectbox.

Issues sqflite in flutter

It's been a while I started flutter. And now I am working on the database part. I started with sqflite since it was the ideal one for offline apps but now I can't understand a thing please can somebody help me with this.
import 'package:flutter/widgets.dart';
import 'note.dart';
import 'package:sqflite/sqflite.dart';
import 'dart:async';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
class DatabaseHelper {
static DatabaseHelper _databaseHelper = DatabaseHelper();
static Database? _database;
String noteTable = 'note_table';
String colID = 'id';
String colTitle = 'title';
String colDescription = 'description';
String colPriority = 'priority';
String colDate = 'date';
DatabaseHelper._createInstance();
factory DatabaseHelper() {
if (_databaseHelper == null) {
var databaseHelper = DatabaseHelper._createInstance();
_databaseHelper = databaseHelper;
}
return _databaseHelper;
}
//custom getter for the database
Future<Database> get database async {
// ignore: prefer_conditional_assignment
if (_database == null) {
_database = await initializeDatabase();
}
return _database!;
}
Future<Database> initializeDatabase() async {
Directory directory = await getApplicationDocumentsDirectory();
String path = directory.path + 'note.db';
var notesDatabase =
await openDatabase(path, version: 1, onCreate: _createDb);
return notesDatabase;
}
void _createDb(Database db, int newVersion) async {
await db.execute(
'CREATE TABLE $noteTable($colID INTEGER PRIMARY KEY AUTOINCREMENT, $colTitle TEXT, $colDescription TEXT, $colPriority INTEGER, $colDate TEXT)');
}
Future<List<Map<String, dynamic>>> getNoteMapList() async {
Database db = await this.database;
var result = await db.query(noteTable, orderBy: '$colPriority ASC');
return result;
}
Future<int> insertData(Note note) async {
Database db = await this.database;
var result = await db.insert(noteTable, note.toMap());
return result;
}
Future<int> updateNote(Note note) async {
Database db = await this.database;
var result = await db
.update(noteTable, note.toMap(), where: '$colID', whereArgs: [note.id]);
return result;
}
Future<int> deleteNote(int id) async {
Database db = await this.database;
var result =
await db.rawDelete('DELETE FROM $noteTable where $colID = $id');
return result;
}
Future<int> getCount() async {
Database db = await this.database;
List<Map<String, dynamic>> x =
await db.rawQuery('SELECT COUNT (*) FROM $noteTable');
int? result = Sqflite.firstIntValue(x);
return result!;
}
Future<List<Note>> getNoteList() async {
var noteMapList = await getNoteMapList();
int count = noteMapList.length;
}
}
This is the whole code. I have watched many videos but can't understand a thing. The problem starts when I the database part starts. And while answering the questions please try to be a little simple.

flutter sqflite DatabaseException no such table

I'm trying to use sqflite here but I keep getting this error when I try to insert values there is no such table but I want to create a table
SqfliteDatabaseException (DatabaseException(no such table: usernotes (code 1 SQLITE_ERROR): , while compiling: INSERT OR REPLACE INTO usernotes (id, title, content) VALUES (?, ?, ?)) sql 'INSERT OR REPLACE INTO usernotes (id, title, content) VALUES (?, ?, ?)' args [2021-03-05 20:44:59.369377, a new note, what should i do]})
here is my database helper class and the controller
import 'package:mynotes/models/note_model.dart';
import 'package:sqflite/sqflite.dart' as sql;
import 'package:path/path.dart' as path;
class DBHelper {
static sql.Database _database;
static Future<void> init() async {
if (_database != null) {
return;
}
try {
var databasePath = await sql.getDatabasesPath();
String _path = path.join(databasePath, 'notes.db');
_database = await sql.openDatabase(_path, version: 1, onCreate: onCreate);
} catch (e) {
print(e);
}
}
static Future onCreate(sql.Database db, int version) async {
await db.execute(
'CREATE TABLE usernotes(id TEXT PRIMARY KEY,title TEXT,content TEXT)');
}
static Future insert(String table, NoteModel noteModel) async =>
await _database.insert(table, noteModel.toMap(),
conflictAlgorithm: sql.ConflictAlgorithm.replace);
}
and here
import 'package:mynotes/helper/db_helper.dart';
import 'package:mynotes/models/note_model.dart';
class NoteController with ChangeNotifier {
List<NoteModel> _notes = [];
List<NoteModel> get notes => _notes;
Future<void> addToNote(String title, String content) async {
try {
await DBHelper.init();
final newNote = NoteModel(
id: DateTime.now().toString(),
title: title,
content: content,
);
_notes.add(newNote);
notifyListeners();
DBHelper.insert(
'usernotes',
NoteModel(
id: newNote.id, title: newNote.title, content: newNote.content));
notifyListeners();
print(notes);
} catch (e) {
print(e);
}
}}
so what is the problem here? I tried to run other project with same functions and this error didn't show
try to switch
static Future<void> init() async {
if (_database != null) {
return;
}
try {
var databasePath = await sql.getDatabasesPath();
String _path = path.join(databasePath, 'notes.db');
_database = await sql.openDatabase(_path, version: 1, onCreate: onCreate);
} catch (e) {
print(e);
}}
to
static Future<Database> init() async {
if (_database != null) return _database;
try {
var databasePath = await sql.getDatabasesPath();
String _path = path.join(databasePath, 'notes.db');
_database = await sql.openDatabase(_path, version: 1, onCreate: onCreate);
return _database;
} catch (e) {
print(e);
}}
because you need to return database here. Next in last segment you need to replace await DBHelper.init(); to db = await DBHelper.init(); and finally DBHelper.insert(... to db.insert(...
I just had to add this line before opening the database
Directory path = await getApplicationDocumentsDirectory();
and use this path
Every time you have modified your database, you need to uninstall the app and reinstall it (or try to increase the schema version in your database).

How to Update a row in Flutter with SQFlite

I try to update a row, but nothing happens, I don't know what I have missed.
Could some please check what I have done wrong ?
This is my helper class.
class DBHelper {
static Future<sql.Database> database() async {
final dbPath = await sql.getDatabasesPath();
//einmal die Datenbank erstellen in einer Variablen
return sql.openDatabase(path.join(dbPath, 'wanderwege.db'),
onCreate: (db, version) {
return db.execute(
'CREATE TABLE user_places(id TEXT PRIMARY KEY, title TEXT, image TEXT, createTime TEXT, place TEXT, description TEXT)');
// 'CREATE TABLE user_places(id TEXT PRIMARY KEY, title TEXT, image TEXT, loc_lat REAL, loc_lng REAL, address TEXT)');
}, version: 1);
}
static Future<void> insert(String table, Map<String, Object> data) async {
final db = await DBHelper.database();
db.insert(table, data, conflictAlgorithm: sql.ConflictAlgorithm.replace);
}
//Delete data from table
static Future<void> delete(String id) async {
final db = await DBHelper.database();
var res = await db.delete('user_places', where: "id = ?", whereArgs: [id]);
return res;
}
//Update Data
static Future<void> updateData(String title) async {
final db = await DBHelper.database();
int res =
await db.rawUpdate('UPDATE user_places SET title = ? WHERE id = ?');
return res;
}
}
And on my Edit_Screen I used this,
first I just wanted to try to update the title, with the new value from _titleController.text
//Update für die jeweiligen einträge zu Kontrollieren
checkupdate() {
if (_titleController.text.isEmpty) {
var errorMessage = 'Bitte gib einen Titel ein';
return _showErrorDialog(errorMessage);
}
DBHelper.updateData(_titleController.text);
print(DBHelper.updateData(_titleController.text));
Navigator.of(context).pop();
}
But nothing happen, I dont now where exactly I have done the misstake.
Thanks for the help :)
I assume you miss update arguments in rawUpdate query.
//Update Data
static Future<void> updateData(String title, String id) async {
final db = await DBHelper.database();
int res =
await db.rawUpdate('UPDATE user_places SET title = ? WHERE id = ?', [title, id]);
return res;
}
Refer rawUpdate example here: https://pub.dev/packages/sqflite

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