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
Related
I have a query I would like to store some data in the cache in the event that the phone is not connected to the Internet and when I connect to the Internet, it is sent to the server. I would like to know the best scenario for this case...
And thank u.
You can try saving the data to the server and on failure you can write it in cache. Like
var response = await http.post(Uri.parse("api url here"),
body: json.encode(body),
);
if(response.statusCode != 200)
{
//save data in local like for example
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString("apiBody", json.encode(body);
}
If you need to store or receive a large amount of data, consider to store this datas in a localdatabase like sqflite: https://pub.dev/packages/sqflite
base on SQLLite, you can store and manipulate data with SQL queries.
Here is an example DB helper call that manipulate customer datas:
class DBProvider {
DBProvider._();
static final DBProvider db = DBProvider._();
late Database _database;
Future<Database> get database async {
_database = await initDB();
return _database;
}
initDB() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(
documentsDirectory.path,
"andidoor.db",
);
return await openDatabase(
path,
version: 2,
onOpen: (db) {},
onCreate: createDatabase,
onUpgrade: upgradeDatabase,
);
}
upgradeDatabase(Database db, int oldVersion, int newVersion) async {
print('Upgrade Database ...');
}
createDatabase(Database db, int version) async {
print('Create Database ...');
await db.execute("CREATE TABLE customers ("
"id INTEGER PRIMARY KEY,"
"user_id INTEGER,"
"company TEXT,"
"address_1 TEXT,"
"address_2 TEXT,"
"address_3 TEXT,"
"zipcode TEXT,"
"city TEXT,"
"country TEXT,"
"email TEXT,"
"phone TEXT,"
"status INTEGER,"
"synced TEXT"
")");
/**
* Customers helper functions
*/
Future<List<dynamic>> getCustomers() async {
Database db = await database;
return await db.rawQuery('SELECT * FROM customers ');
}
Future<void> populateCustomers(List<dynamic> customers) async {
final completer = Completer();
await deleteAllcustomers();
for (var i = 0; i < customers.length; i++) {
await addCustomer(Customer.fromMap(customers[i]), true);
}
completer.complete();
return completer.future;
}
Future<dynamic> deleteAllcustomers() async {
Database db = await database;
return await db.rawQuery('DELETE FROM customers');
}
Future<dynamic> deleteCustomer(String customerID) async {
final db = await database;
return db.delete(
"customers",
where: "id = ? ",
whereArgs: [customerID],
);
}
}
And in other dart file just use like this:
final db = DBProvider.db;
List<dynamic> allDatas = [];
allDatas = await db.getCustomers();
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.
I am receiving a null value when I am saving a value as in my code I have three fields
String? _itemName ="";
String? _dateCreated ="";
int? _id;
and when after running my project, I insert an item by calling this method:
Future<int> saveItem(NoDoItem item) async
{
var dbClient = await database;
int res = await dbClient.insert(tableName, item.toMap());
debugPrint(res.toString());
return res;
}
Using saveItem() function:
void _hndleSubmitted(String text) async
{
_textEditingController.clear();
NoDoItem noDoItem = NoDoItem(text, DateTime.now().toIso8601String());
int savedItemId = await db.saveItem(noDoItem);
debugPrint("Item saved ID: $savedItemId");
}
and after this when I am retrieving all itemNames, I get null value instead of user entered value
Defining getItems() func:
Future<List> getItems() async
{
var dbClient = await database;
var result = await dbClient.rawQuery("SELECT * FROM $tableName ORDER BY $columnItemName ASC");
return result.toList();
}
Using getItems() function:
_readNotoDoItems() async
{
List items = await db.getItems();
items.forEach((item) {
NoDoItem noDoItem = NoDoItem.map(item);
print("Db items: ${noDoItem.itemName}");
});
}
Please tell me what is the the reason that I am getting a null value instead of entered value and how to fix this issue?
I think the problem is here
void _hndleSubmitted(String text) async {
_textEditingController.clear(); // <--------- HERE
NoDoItem noDoItem = NoDoItem(text, DateTime.now().toIso8601String());
int savedItemId = await db.saveItem(noDoItem);
debugPrint("Item saved ID: $savedItemId");
}
you clear the value with _textEditingController.clear(); right before using it. move it after adding the item to database
void _hndleSubmitted(String text) async {
NoDoItem noDoItem = NoDoItem(text, DateTime.now().toIso8601String());
int savedItemId = await db.saveItem(noDoItem);
textEditingController.clear();
debugPrint("Item saved ID: $savedItemId");
}
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]);}
import 'dart:io';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
class DatabaseHelper {
static final _databaseName = "MyDatabase.db";
static final _databaseVersion = 1;
static final table = 'my_table';
static final columnId = '_id';
static final columnName = 'name';
static final columnAge = 'age';
// make this a singleton class
DatabaseHelper._privateConstructor();
static final DatabaseHelper instance = DatabaseHelper._privateConstructor();
// only have a single app-wide reference to the database
static Database _database;
Future<Database> get database async {
if (_database != null) return _database;
// lazily instantiate the db the first time it is accessed
_database = await _initDatabase();
return _database;
}
// this opens the database (and creates it if it doesn't exist)
_initDatabase() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, _databaseName);
return await openDatabase(path,
version: _databaseVersion,
onCreate: _onCreate);
}
// SQL code to create the database table
Future _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE $table (
$columnId INTEGER PRIMARY KEY,
$columnName TEXT NOT NULL,
$columnAge INTEGER NOT NULL
)
''');
}
// Helper methods
// Inserts a row in the database where each key in the Map is a column name
// and the value is the column value. The return value is the id of the
// inserted row.
Future<int> insert(Map<String, dynamic> row) async {
Database db = await instance.database;
return await db.insert(table, row);
}
// All of the rows are returned as a list of maps, where each map is
// a key-value list of columns.
Future<List<Map<String, dynamic>>> queryAllRows() async {
Database db = await instance.database;
return await db.query(table);
}
// All of the methods (insert, query, update, delete) can also be done using
// raw SQL commands. This method uses a raw query to give the row count.
Future<double> queryRowCount() async {
Database db = await instance.database;
List<Map<String, dynamic>> x = await db.rawQuery('SELECT COUNT(*) FROM $table');
int rowCount = Sqflite.firstIntValue(x);
return rowCount.toDouble();
}
// We are assuming here that the id column in the map is set. The other
// column values will be used to update the row.
Future<int> update(Map<String, dynamic> row) async {
Database db = await instance.database;
int id = row[columnId];
return await db.update(table, row, where: '$columnId = ?', whereArgs: [id]);
}
// Deletes the row specified by the id. The number of affected rows is
// returned. This should be 1 as long as the row exists.
Future<int> delete(int id) async {
Database db = await instance.database;
return await db.delete(table, where: '$columnId = ?', whereArgs: [id]);
}
Future<List<Map<String, dynamic>>> queryOmnivore() async {
Database db = await instance.database;
return await db.query(table, where: '$columnName = ?', whereArgs: ['omnivore']);
}
Future<List<Map<String, dynamic>>> queryPescatarian() async {
Database db = await instance.database;
return await db.query(table, where: '$columnName = ?', whereArgs: ['pescatarian']);
}
Future<List<Map<String, dynamic>>> queryVegetarian() async {
Database db = await instance.database;
return await db.query(table, where: '$columnName = ?', whereArgs: ['vegetarian']);
}
Future<int> queryVegetarianCount() async {
var vegList = await queryVegetarian();
int count = vegList.length;
return count;
}
Future<double> queryOmnivoreCount() async {
var omniList = await queryOmnivore();
int omniCount = omniList.length;
return omniCount.toDouble();
}
Future<double> calcOmnivorePercentage() async {
var x = await queryOmnivoreCount();
var y = await queryRowCount();
double omniPercentage = (x / y) * 100;
return omniPercentage;
}
}
Hey Folks!
I was hoping someone may be able to help me please?!
I'm trying to figure out how to take data out of a a sqflite table I've created, perform a calculation that expresses it as a percentage of the other values, and display it inside a text widget in the app.
I've actually managed to get the result to print in the console using this code:
void omnivorePercentageQ() async {
final omni = await dbHelper.calcOmnivorePercentage();
print('omnivore percentage: ${omni.toStringAsFixed(1)}');
}
But I have no idea how to get it to show up in a text widget in the app itself.
Any ideas would be greatly appreciated!
Thank you,
Jason
you are not far off the answer, and already catch the value of the calculation needed. As i can see you dont need to pass any parameters to the function so i would recomend using a futurebuilder:
return FutureBuilder(
future: dbHelper.calcOmnivorePercentage(),
builder: (context, AsyncSnapshot<double> snapshot) {
if (snapshot.hasData) {
return Center( child: Text('${snapshot.data.toStringAsFixed(1)}'),);
}else
return Center(
child: CupertinoActivityIndicator(),
);
});
The Future Builder class https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html
Serves to manage widgets that depend on futures, since your calculation and database querys are async you can check its state (As inside the widget in snapshot.hasData). That conditional checks if the future has finished and else shows an indicator. Hope it helps