How to get the total of column values in sqflite in flutter? - flutter

I want to get the total of the price column values and save it in a variable and return it...I have gone through other posts one of which is the question which i am asking but it was in android native and i am new to sqflite so i couldnt figure out how to write the code. So please help me with suggestions.
this is my code of the columns i am using
void _onCreate(Database db, int version) async {
await db.execute(
"CREATE TABLE Cart(id INTEGER PRIMARY KEY,name TEXT, price TEXT,category
TEXT,images TEXT)");
print("DB created");
}
I am trying to do this
Future calculateTotal() async{
var dbClient = await db;// couldnt figure out after this
var cursor = dbClient.rawQuery("SELECT SUM(price) as Total FROM Cart",
null);
if(cursor.move)
}

According to https://www.techiediaries.com/flutter-sqlite-crud-tutorial/ this should do:
Future calculateTotal() async {
var dbClient = await db;
var result = await dbClient.rawQuery("SELECT SUM(price) as Total FROM Cart");
print(result.toList());
}
int _total;
void _calcTotal() async{
var total = (await db.calculateTotal())[0]['Total'];
print(total);
setState(() => _total = total)
}
#override
Widget build(BuildContext context) {
...
Text(_total != null ? _total : 'waiting ...', ... )

Future<List> calculateTotal() async {
var dbClient = await db;
var result = await dbClient.rawQuery("SELECT * FROM Cart");
return result.toList();
}
int _total = 0;
List priceList;
void _calcTotal() async{
priceList = await db.calculateTotal();
priceList.forEach((price){ _total = _total + price['price'];});
print(_total);
setState(() => _total = total);
}
#override
Widget build(BuildContext context) {
...
Text(_total != null ? _total : 'waiting ...', ... )

Related

Sqflite get locked on bulk insertion even after using transaction object and batch

I am new to flutter and I am doing bulk insertion in sqflite database. I have tried using both transaction and batch objects but my issue still remains there and database gets locked.
Here is what i am doing.
Future<List<ShopsModel>> fetchShops() async{
int count = 0;
List<ShopsModel> shopsList = [];
int id = 0;
String date = "";
List<SyncDataModel> syncList = await DatabaseHelper.instance.getSyncDataHistory();
syncList.forEach((element) {
id = element.SyncID!;
date = element.ShopSyncDate == null ? "" : element.ShopSyncDate!;
});
//Info.startProgress();
String response = await ApiServices.getMethodApi("${ApiUrls.IMPORT_SHOPS}?date=$date");
if(response.isEmpty || response == null){
return shopsList;
}
var shopsApiResponse = shopsApiResponseFromJson(response);
if(shopsApiResponse.data != null){
shopsApiResponse.data!.forEach((element) async{
await insertShops(element);
count++;
if(count == 1){
syncList.length == 0 ? await DatabaseHelper.instance.insertSyncDataHistory(
SyncDataModel(
ShopSyncDate: DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()),
LastSyncDate: DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now())
)) :
await DatabaseHelper.instance.updateShopSyncDate(
DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()), id);
}
});
}
return shopsList;
}
Future insertShops(ShopsModel row) async{
var shopsRow = await DatabaseHelper.instance.getShopByShopId(row.shopID!);
if(shopsRow.IsModify == 0 || shopsRow.IsModify == null) {
var result = await DatabaseHelper.instance.deleteImportedShops(
row.shopID!, DateFormat('yyyy-MM-dd HH:mm:ss').format(
DateTime.parse(row.updatedOn!)));
if (result > 0) {
print('Shop has been deleted');
}
await DatabaseHelper.instance.insertShops(
ShopsModel(
shopID: row.shopID,
shopName: row.shopName,
shopCode: row.shopCode,
contactPerson: row.contactPerson,
contactNo: row.contactNo,
nTNNO: row.nTNNO,
regionID: row.regionID,
areaID: row.areaID,
salePersonID: row.salePersonID,
createdByID: row.createdByID,
updatedByID: row.updatedByID,
systemNotes: row.systemNotes,
remarks: row.remarks,
description: row.description,
entryDate: DateFormat('yyyy-MM-dd HH:mm:ss').format(
DateTime.parse(row.entryDate!)),
branchID: row.branchID,
longitiude: row.longitiude,
latitiude: row.latitiude,
googleAddress: row.googleAddress,
createdOn: DateFormat('yyyy-MM-dd HH:mm:ss').format(
DateTime.parse(row.createdOn!)),
updatedOn: DateFormat('yyyy-MM-dd HH:mm:ss').format(
DateTime.parse(row.updatedOn!)),
tradeChannelID: row.tradeChannelID,
route: row.route,
vPO: row.vPO,
sEO: row.sEO,
imageUrl: row.imageUrl,
IsModify: 0
)
);
}
}
// Below are my Database methods
Future<int> deleteImportedShops(int shopID, String updatedDate) async{
Database db = await instance.database;
return await db.delete("$shopsTable", where: 'ShopID = ? AND UpdatedOn <= ?', whereArgs: [shopID, updatedDate]);
}
Future<void> insertShops(ShopsModel shopsRow) async{
Database db = await instance.database;
await db.transaction((txn) async {
var batch = txn.batch();
batch.insert("$shopsTable", shopsRow.toJson(), conflictAlgorithm: ConflictAlgorithm.replace);
await batch.commit();
});
}
Future<void> insertSyncDataHistory(SyncDataModel row) async{
Database db = await instance.database;
await db.transaction((txn) async {
var batch = txn.batch();
batch.insert("$syncDataTable", row.toJson(), conflictAlgorithm: ConflictAlgorithm.replace);
await batch.commit();
});
}
Future<void> updateShopSyncDate(String? pDate, int id) async{
Database db = await instance.database;
await db.transaction((txn) async {
var batch = txn.batch();
batch.rawUpdate("UPDATE SyncDataHistory SET ShopSyncDate = ?, LastSyncDate = ? WHERE SyncID = ?", [pDate, pDate, id]);
await batch.commit();
});
}
Here are the details what I am getting as an output.
Warning database has been locked for 0:00:10.000000. Make sure you always use the transaction object for database operations during a transaction
Please help me out. Any help would be appreciated.

Stack Overflow error when adding item to cart using sqflite

i am trying to add product to cart using local database but its giving error stack overflow
here is my cart provider class
class CartProvider with ChangeNotifier {
DBHelper db = DBHelper();
int _counter = 0;
int get counter => _counter;
double _totalPrice = 0.0;
double get totalPrice => _totalPrice;
late Future<List<Cart>> _cart;
Future<List<Cart>> get cart => _cart;
Future<List<Cart>> getData() async {
_cart = db.getCartList();
return _cart;
}
void _setPrefItems() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setInt('cart_item', _counter);
prefs.setDouble('total_price', _totalPrice);
notifyListeners();
}
void _getPrefsItems() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
_counter = prefs.getInt('cart_item') ?? 0;
_totalPrice = prefs.getDouble('total_price') ?? 0.0;
notifyListeners();
}
void addCounter (){
_counter++;
_setPrefItems();
notifyListeners();
}
void removeCounter (){
_counter--;
_setPrefItems();
notifyListeners();
}
int getCounter(){
_getPrefsItems();
_counter++;
return _counter;
}
void addTotalPrice (double productPrice){
_totalPrice = _totalPrice + productPrice;
_setPrefItems();
notifyListeners();
}
void removeTotalPrice (double productPrice){
_totalPrice = _totalPrice - productPrice;
_setPrefItems();
notifyListeners();
}
double getTotalPrice(){
_getPrefsItems();
return _totalPrice ;
}
}
here is how i am adding it to cart on button click i am getting product from product model class
InkWell(
onTap: () {
dbHelper.insert(
Cart(
id: widget.products.id,
productId: widget.products.id.toString(),
initialPrice: widget.products.price.round(),
productPrice: widget.products.price.round(),
image: widget.products.image,
productName: widget.products.title,
cartDescription: widget.products.description,
quantity: 1,
)
).then((value) {
cart.addTotalPrice(widget.products.price);
cart.addCounter();
print('add to cart');
}).onError((error, stackTrace) {
print(error.toString());
print('error');
});
my database class where i am creating local database where i insert and create database table
class DBHelper {
static Database? _db;
Future<Database?> get db async {
if (_db != null) {
return db;
}
_db = await initDatabase();
}
initDatabase() async {
io.Directory documentDirectory = await getApplicationDocumentsDirectory();
String path = join(documentDirectory.path, 'cart.db');
var db = await openDatabase(path, version: 1, onCreate: _oncreate);
return db;
}
_oncreate(Database db, int version) async {
await db.execute(
'CREATE TABLE cart (id INTEGER PRIMARY KEY, productId VARCHAR UNIQUE, productName TEXT, initialPrice INTEGER, productPrice INTEGER, quantity INTEGER, cartDescription TEXT, image TEXT)');
}
Future<Cart> insert(Cart cart) async {
var dbClient = await db;
await dbClient!.insert('cart', cart.toMap());
return cart;
}
Future<List<Cart>> getCartList() async {
var dbClient = await db;
final List<Map<String, Object?>> queryResult =
await dbClient!.query('cart');
return queryResult.map((e) => Cart.fromMap(e)).toList();
}
}
kindly help me out when i am adding it to cart its simply print
I/flutter ( 4595): Stack Overflow
on stack trace error
I/flutter ( 6159): #0 DBHelper.insert (package:heem/database/bd_helper.dart:34:19)
I/flutter ( 6159): <asynchronous suspension>
I/flutter ( 6159): #1 FutureExtensions.onError.<anonymous closure> (dart:async/future.dart:1013:15)
I/flutter ( 6159): <asynchronous suspension>
I think the problem is in this getter:
Future<Database?> get db async {
if (_db != null) {
return db;
}
_db = await initDatabase();
}
In return db; you have infinite recursion.
Generally speaking, getters that perform async work are a code smell. Also, what if somebody calls this getter multiple times in parallel?
In my opinion, you should either:
Expose initDatabase method. In every other method require that database is already initialized. This way, you're delegating the responsibility of ensuring initialization before any other operation is performed to the caller of this service (probably your business logic layer). Briefly documenting this assumptions would also be a good idea.
Create a private _ensureInitialized() method which will encapsulate all the logic necessary to ensure correctness:
Completer<Database>? _initCompleter;
Database? _database;
Future<Database> _ensureInitialized() async {
if(_database != null) return _database;
if(_initCompleter != null) return await _initCompleter!.future;
_initCompleter = Completer<Database>();
final database = await _initDatabase();
_database = database;
_initCompleter.complete(database);
return database;
}
Future<void> insert(...) async {
final database = await _ensureInitialized();
...
}

Getting null value instead of input value in flutter

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

Unable to display ListView from SqFLite

My data is able to upload to the database without any error, however i cant seem to display my listview with the data.
As you can see from the _submit() function, if theres an error, snackbar will be shown indicating theres an error and will not proceed to the mainpage, however, the result shows a snackbar with a success message,
So Im suspecting it has to do with my listview code, or my databasehelper as I may have missed out something in the code.
Any help is deeply appreciated!
Heres my listview code:
FutureBuilder<List<Note>>(
future: _databaseHelper.getNoteList(),
builder: (BuildContext context, AsyncSnapshot<List<Note>> snapshot){
if(snapshot.hasData){
return ListView.builder(
itemCount: _count,
itemBuilder: (BuildContext context, int position) {
Note note = snapshot.data[position];
return Card(
color: Colors.white,
elevation: 2.0,
child: new ListTile(
title: new Text(note.title),
subtitle: new Text(note.bodyText),
onTap: () =>
_navigateToEditAddPage(note, 'Edit a Note'),
onLongPress: () => _showDeleteDialog(note),
),
);
});
}else{
return Container(width: 0,height: 0,);
}
},),
Heres my insertData code:
void _submit() async {
if (_formKey.currentState.validate()) {
note.title = _titleController.text;
note.bodyText = _bodyTextController.text;
note.date = _dateController.text;
if (note.id == null) {
int result = await _databaseHelper.insertData(note);
if (result != 0) {
_moveToHomePage('Note successfully added');
} else {
_showSnackBar('Note unable to be inserted due to some error');
}
} else {
int result = await _databaseHelper.updateData(note);
if (result != 0) {
_moveToHomePage('Note successfully updated');
} else {
_showSnackBar('Note unable to be updated due to some error');
}
}
}
}
Heres my DatabaseHelper code:
class DatabaseHelper {
static Database _database;
String dataTable = 'NoteTable';
String colId = 'id';
String colTitle = 'title';
String colBody = 'bodyText';
String colDate = 'date';
DatabaseHelper._();
static final DatabaseHelper db = DatabaseHelper._();
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 + 'notes.db';
var notesDatabase =
await openDatabase(path, version: 1, onCreate: _createDb);
return notesDatabase;
}
void _createDb(Database database, int newVersion) async {
await database.execute("CREATE TABLE $dataTable ("
"$colId INTEGER PRIMARY KEY AUTOINCREMENT,"
"$colTitle TEXT,"
"$colBody TEXT,"
"$colDate TEXT"
")");
}
Future<List<Map<String, dynamic>>> getNoteListMap() async {
Database db = await this.database;
var result = await db.query(dataTable);
return result;
}
Future<int> insertData(Note note) async {
Database db = await this.database;
var result = await db.insert(dataTable,note.toMap(),conflictAlgorithm:
ConflictAlgorithm.replace,);
return result;
}
Future<int> updateData(Note note) async {
Database db = await this.database;
var result = await db.update(dataTable,note.toMap(),
where: 'colId = ?', whereArgs: [note.id]);
return result;
}
Future<int> deleteData(Note note) async {
Database db = await this.database;
var result = await db
.delete(dataTable, where: 'colId = ?', whereArgs: [note.id]);
return result;
}
Future<int> getCount() async{
Database db = await this.database;
List<Map<String,dynamic>> x = await db.rawQuery('SELECT COUNT (*) from $dataTable');
int result = Sqflite.firstIntValue(x);
return result;
}
Future<List<Note>> getNoteList() async {
var noteMapList = await getNoteListMap();
int count = noteMapList.length;
//list of notes, each note consist of their own independent variables
List<Note> noteList;
for (int i = 0; i < count; i++) {
noteList.add(Note.fromMapObject(noteMapList[i]));
}
return noteList;
}
}
And lastly my Note model:
class Note {
int _id;
String _date;
String _title;
String _bodyText;
Note(this._date, this._title, this._bodyText);
Note.withId(this._id, this._date, this._title, this._bodyText);
set date(String date) {
this._date = date;
}
get date => _date;
set title(String title) {
this._title = title;
}
get title => _title;
set bodyText(String bodyText){
this._bodyText = bodyText;
}
get bodyText => _bodyText;
get id => _id;
Map<String, dynamic> toMap() {
var map = new Map<String, dynamic>();
if (_id != null) {
map['id'] = _id;
}
map['title'] = _title;
map['bodyText'] = _bodyText;
map['date'] = _date;
return map;
}
//Converting a map object to a note object
Note.fromMapObject(Map<String,dynamic> fromMap){
_id = fromMap['id'];
_title = fromMap['title'];
_bodyText = fromMap['bodyText'];
_date = fromMap['date'];
}
}
I found two errors in your code.
1: in getNoteList() of DatabaseHelper
List<Note> noteList;
to
List<Note> noteList = [];
2: in listview code
itemCount: _count,
to
itemCount: snapshot.data.length,
result:

Why the Id of object addedItem is always return 1 until I refresh page

I want to get the real Id of object how's I create in real time without close page and return back to it
because I use initState() to get data from Database and if I tried to get Id without do that it will return 1 ;
any one know why this happened and who to fix it ?
this my Function:
item(String name,String desc,int rate) async{
int savedItem = await db.saveMovie(Movie(name, desc,rate.toString()));
Movie addedItem = await db.getMovie(savedItem);
setState(() {
movies.add(addedItem);
});
print("Item id :${addedItem.id} Saved item : ${savedItem}");
}
and this my database helper code :
import 'dart:async';
import 'package:sqflite/sqflite.dart';
import 'dart:io';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:mblists/models/movies.dart';
class DatabaseHelper {
final String moviesTable = "moviesTable";
final String idColumn = "id";
final String nameColumn = "name";
final String descriptionColumn = "description";
final String rateColumn = "rate";
static final DatabaseHelper _instance = DatabaseHelper.internal();
factory DatabaseHelper() => _instance;
static Database _db;
Future<Database> get db async{
if(_db != null){
return _db;
}
_db = await initDb();
return _db;
}
DatabaseHelper.internal();
initDb() async{
Directory fileDirectory = await getApplicationDocumentsDirectory();
String path = join(fileDirectory.path,"maindatabase.db");
var maindb = await openDatabase(path,version: 1,onCreate: _onCreate);
return maindb;
}
void _onCreate(Database db,int newVersion) async{
await db.execute(
"CREATE TABLE $moviesTable($idColumn INTEGER PRIMARY KEY, $nameColumn TEXT, $descriptionColumn TEXT, $rateColumn TEXT)");
}
Future<int> saveMovie(Movie movie) async{
var dbClient = await db;
int res = await dbClient.insert("$moviesTable", movie.toMap());
return res;
}
Future<List> getAllMovies() async{
var dbClient = await db;
var result = await dbClient.rawQuery("SELECT * FROM $moviesTable");
return result;
}
Future<Movie> getMovie(int id) async{
var dbClient = await db;
var result = await dbClient.rawQuery("SELECT * FROM $moviesTable WHERE $id = $id");
if(result.length == 0) {
return null;
}
return Movie.formMap(result.first);
}
Future<int> getCount() async {
var dbCllient = await db;
return Sqflite.firstIntValue(
await dbCllient.rawQuery("SELECT COUNT(*) FROM $moviesTable")
);
}
Future<int> deleteMovie(int id) async {
var dbClient = await db;
return await dbClient.delete(moviesTable,where: "$idColumn = ?",whereArgs: [ id]);
}
Future<int> deleteMovies() async {
var dbClient = await db;
return await dbClient.delete(moviesTable);
}
Future<int> updateMovie(Movie movie) async {
var dbClient = await db;
return await dbClient.update(moviesTable,movie.toMap(),
where: "$idColumn = ?" , whereArgs: [movie.id]
);
}
Future colse() async{
var dbClient = await db;
return await dbClient.close();
}
}
Insert method returns correct new id, but you have a typo in getMovie:
var result = await dbClient.rawQuery("SELECT * FROM $moviesTable WHERE $id = $id");
WHERE condition should contain column name, but your has id = id condition (which is always true) and then it takes the first element (always the same one). Fix it by passing id column's name:
var result = await dbClient.rawQuery("SELECT * FROM $moviesTable WHERE $idColumn = $id");
And it works:
I/flutter ( 5996): Item id :13 Saved item : {id: 13, name: test, description: desc, rate: 1}
I/flutter ( 5996): Item id :14 Saved item : {id: 14, name: test, description: desc, rate: 1}
I/flutter ( 5996): Item id :15 Saved item : {id: 15, name: test, description: desc, rate: 1}