how to store all data with flutter sqlite? - sqlite

i am using sqflite package to store and get data from storage but i realized that all data are not stored altough i used the insert sqlfite function as below :
static Future insertData(String table, data) async {
Database db = await DatabaseHelper.database;
var result = await db.insert('$table', data,
conflictAlgorithm: ConflictAlgorithm.replace);
print("resultat $result");
return result;
}
and just in case i did not do it well, the database initialization and creation :
class DatabaseHelper {
static DatabaseHelper _databaseHelper;
static Database _database;
DatabaseHelper._createInstance();
static final DatabaseHelper instance = DatabaseHelper._createInstance();
factory DatabaseHelper() {
if (_databaseHelper == null) {
_databaseHelper = DatabaseHelper._createInstance();
}
return _databaseHelper;
}
static Future<Database> get database async {
if (_database == null) {
_database = await initializeDatabase();
}
return _database;
}
static Future<Database> initializeDatabase() async {
Directory directory = await getApplicationSupportDirectory();
String path = directory.path + 'mpata.db';
var mpataDatabase =
await openDatabase(path, version: 1, onCreate: _createDb);
return mpataDatabase;
}
static void _createDb(Database db, int newVersion) async {
await db.execute(
'CREATE TABLE operationType(operationTypeId INTEGER PRIMARY KEY, libelle TEXT);');
await db.execute(
'CREATE TABLE accounType(accountTypeId INTEGER PRIMARY KEY, libelle TEXT);');
await db.execute(
'CREATE TABLE country(countryIsoCode INTEGER PRIMARY KEY, name TEXT);');
await db.execute(
'CREATE TABLE user(userId INTEGER PRIMARY KEY, email TEXT, firstName TEXT, lastName TEXT, msisdnUsr TEXT);');
await db.execute(
'CREATE TABLE otheruser(userId INTEGER PRIMARY KEY, email TEXT, firstName TEXT, lastName TEXT, msisdnUsr TEXT);');
await db.execute(
'CREATE TABLE accounts(accountId INTEGER PRIMARY KEY,active INTEGER,country TEXT,createDate TEXT,currency TEXT,expire TEXT,msisdn TEXT,numero TEXT,pin TEXT,solde DOUBLE,updateDate TEXT);');
await db.execute(
'CREATE TABLE other(accountId INTEGER PRIMARY KEY,active INTEGER,country TEXT,createDate TEXT,currency TEXT,expire TEXT,msisdn TEXT,numero TEXT,pin TEXT,solde DOUBLE,updateDate TEXT);');
await db.execute(
'CREATE TABLE transactions(id INTEGER PRIMARY KEY,account INTEGER,other INTEGER,amount INTEGER,fees INTEGER,operationDate TEXT,operationTypeId INTEGER,reference TEXT,status TEXT,frais INTEGER,description TEXT,admin TEXT,libelleOperation TEXT,accountId INTEGER,userId INTEGER,firstName TEXT,lastName TEXT,email TEXT,msisdnUsr TEXT);');
await db.execute(
'CREATE TABLE productCategory(productCategoryId INTEGER PRIMARY KEY,libelle TEXT, description TEXT);');
await db.execute(
'CREATE TABLE notification(notificationId INTEGER PRIMARY KEY,notificationType TEXT, message TEXT, statut TEXT, createDate TEXT);');
await db.execute(
'CREATE TABLE notifications(notificationId INTEGER PRIMARY KEY,notificationType TEXT, message TEXT, statut TEXT, createDate TEXT);');
}
}
and finally the way i store each item i received from online mode:
var dataUserAccount = {
'userId': item['account']['user']['userId'],
'email': item['account']['user']['email'],
'firstName': item['account']['user']['firstName'],
'lastName': item['account']['user']['lastName'],
'msisdnUsr': item['account']['user']['msisdn']
};
var idusr = await DatabaseHelper.insertData('user', dataUserAccount);
i am using sqflite to apply offline on my application, and when i realize some tests, the results in online mode are greater than the one with offline mode. and i print the raws number of the sqlite tables and the length of the results got from a web service. there are not the same. so i don't know why the insert function is not working for all cases.

Related

return a string value in flutter sqlite database

i want to get username String value for the specific deviceId from database but i am getting this error
UserName===Instance of 'Future<List<Map<String, dynamic>>>
I can insert data successfully in table, only the problem in returning the value.
here is my code:
declaring database and columns:
static final _databaseName = "MyDatabase.db";
static final _databaseVersion = 1;
static final table = 'my_table';
static final columnId = '_id';
static final columnName = 'name';
static final columnPassword = 'password';
static final columnDeviceID = 'deviceID';
///....
////...
Future _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE $table (
$columnId INTEGER PRIMARY KEY,
$columnName STRING NOT NULL,
$columnPassword STRING NOT NULL,
$columnDeviceID STRING NOT NULL UNIQUE
)
''');
}
get Name method
Future<String> getName(String deviceid) async{
Database db = await instance.database;
String name= await columnName;
db.rawQuery('SELECT $name FROM $table WHERE $columnDeviceID = $deviceid');
return name;
}
and here is how am using getName method in app to get the value:
String user_name = await dbHelper.getName(deviceId);

Can't create a database. No db in device file explorer

I am trying to make a little project in Flutter where I add some data in a form along with a few images in the sqflite database, but I can't figure out why exactly my code isn't working.
Here is my db_helper class
Future<Database> get db async {
if (_db != null)
return _db;
_db = await initDb();
return _db;
}
//Creating a database with name test.dn in your directory
initDb() async {
io.Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, "products.db");
var theDb = await openDatabase(path, version: 1, onCreate: _onCreate);
return theDb;
}
// Creating a table name Employee with fields
void _onCreate(Database db, int version) async {
// When creating the db, create the table
await db.execute(
"""CREATE TABLE product(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
brand TEXT NOT NULL,
color TEXT NOT NULL,
size INTEGER NOT NULL,
qty INTEGER NOT NULL)""");
await db.execute(
"""CREATE TABLE image(
id INTEGER PRIMARY KEY AUTOINCREMENT,
path TEXT,
product_id INTEGER,
FOREIGN KEY(product_id) REFERENCES product (id)
ON DELETE NO ACTION ON UPDATE NO ACTION)""");
debugPrint("Created tables");
}
// Get all products
Future<List<Map<String, dynamic>>> getProducts() async {
Database db = this.initDb();
var result = await db.query('product');
return result;
}
// Inser or update image
Future<product_model.Image> insertImage(product_model.Image image) async {
// var count = Sqflite.firstIntValue(await _db.rawQuery("SELECT COUNT(*) FROM image WHERE username = ?", [image.id]));
Database database = await db;
await database.insert("image", image.toMap(), conflictAlgorithm: ConflictAlgorithm.ignore);
// await _db.update("image", image.toMap(), where: "id = ?", whereArgs: [image.id]);
return image;
}
// Inser or update product
Future<product_model.Product> insertProduct(product_model.Product product) async {
// var count = Sqflite.firstIntValue(await _db.rawQuery("SELECT COUNT(*) FROM product WHERE username = ?", [product.id]));
Database database = await db;
await database.insert("product", product.toMap(), conflictAlgorithm: ConflictAlgorithm.ignore);
// await _db.update("product", product.toMap(), where: "id = ?", whereArgs: [product.id]);
return product;
}
And here is where I call the db:
void _saveProductWithPictures() async{
db = DBHelper();
// var db = await dbHelper.initDb();
product = db_elements.Product();
imageModels = List<db_elements.Image>();
int result;
await db.insertProduct(product).whenComplete(() => {
_nameController.clear(),
_brandController.clear(),
_colorController.clear(),
_sizeController.clear(),
_qtyController.clear()
});
if (result != 0) { // Success
_showAlertDialog('Status', 'Note Saved Successfully');
} else { // Failure
_showAlertDialog('Status', 'Problem Saving Note');
}
//save the product
// end save the product
//save the product picture/s
for (var i in _files) imageModels.add(db_elements.Image(path: i.path.toString()));
for (var image in imageModels) await db.insertImage(image).whenComplete(() => {
_files.clear()
});
//end save the product picture/s
}
I tried for weeks to fix this, but still hopeless. I can't save data to the database. Appreciate any kind of help. Thanks in advance

How to insert POJO Objects and Lists in SQFlite

I am trying to store data from an API to sqflite , but I have to insert the Objects and the Lists, however during the process, am getting this error :
ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: DatabaseException(java.lang.String cannot be cast to java.lang.Integer) sql 'INSERT INTO articleTable (id, created_on, title, summary, details, tags, featured_image, author, category) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)' args [21, 2020-04-14 04:04:57, Singer Jose ...}]
This is the Model Article class :
#JsonSerializable(explicitToJson: true)
class Article {
Article(this.id, this.created_on, this.title, this.details,
this.featured_image, this.author, this.category, this.summary, this.tags);
int id;
String created_on;
String title;
String summary;
String details;
List<String> tags;
String featured_image;
Author author;
Category category;
factory Article.fromJson(Map<String, dynamic> json) =>
_$ArticleFromJson(json);
Map<String, dynamic> toJson() => _$ArticleToJson(this);
}
The automated generated file for Article model class :
/ GENERATED CODE - DO NOT MODIFY BY HAND
part of 'article.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Article _$ArticleFromJson(Map<String, dynamic> json) {
return Article(
json['id'] as int,
json['created_on'] as String,
json['title'] as String,
json['details'] as String,
json['featured_image'] as String,
json['author'] == null
? null
: Author.fromJson(json['author'] as Map<String, dynamic>),
json['category'] == null
? null
: Category.fromJson(json['category'] as Map<String, dynamic>),
json['summary'] as String,
(json['tags'] as List)?.map((e) => e as String)?.toList(),
);
}
Map<String, dynamic> _$ArticleToJson(Article instance) => <String, dynamic>{
'id': instance.id,
'created_on': instance.created_on,
'title': instance.title,
'summary': instance.summary,
'details': instance.details,
'tags': instance.tags,
'featured_image': instance.featured_image,
'author': instance.author?.toJson(),
'category': instance.category?.toJson(),
};
This is where am doing my Sqflite insertion :
class ArticleApiProvider {
Future<List<Article>> fetchArticles() async {
final response =
await http.get('https://api.xyxyxyxy');
if (response.statusCode == 200) {
List jsonResponse = jsonDecode(response.body);
return jsonResponse.map((article) {
articleBloc.addArticles(Article.fromJson(article));
}).toList();
} else {
throw Exception('Failed to retrieve articles');
}
}
}
My Bloc Class :
class ArticleBloc {
final _repository = Repository();
final _articleFetcher = PublishSubject<List<Article>>();
Stream<List<Article>> get allArticles => _articleFetcher.stream;
fetchArticles() async {
List<Article> articles = await _repository.fetchArticles();
_articleFetcher.sink.add(articles);
}
getArticlesCached() async {
// sink is a way of adding data reactively to the stream
// by registering a new event
_articleFetcher.sink.add(await _repository.getAllArticles());
}
void addArticles(Article article) async {
await _repository.insertArticle(article);
}
dispose() {
_articleFetcher.close();
}
}
final articleBloc = ArticleBloc();
This is the DatabaseProvider class
final articlesTable = "articleTable";
class DatabaseProvider {
static final DatabaseProvider dbProvider = DatabaseProvider();
Database _database;
String id = "id";
String createdOn = "created_on";
String title = "title";
String summary = "summary";
String details = "details";
String featuredImage = "featured_image";
String author = "author";
String category = "category";
String tags = "tags";
Future<Database> get database async {
if (_database != null) return _database;
_database = await createDatabase();
return _database;
}
createDatabase() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
// NewVision.db is our database instance name
String path = join(documentsDirectory.path, "NewVision.db");
var database = await openDatabase(path,
version: 1, onCreate: initDB, onUpgrade: onUpgrade);
return database;
}
void initDB(Database db, int version) async {
await db.execute(
'CREATE TABLE $articlesTable($id INTEGER PRIMARY KEY AUTOINCREMENT, $createdOn TEXT, $title TEXT ,'
' $summary TEXT , $details TEXT , '
'$tags TEXT, $featuredImage TEXT , $author TEXT , $category TEXT )');
}
void onUpgrade(Database db, int oldVersion, int newVersion) {
if (newVersion > oldVersion) {}
}
}
String join(String path, String s) {
return path + s;
}
The rest of the files do follow the Bloc architecture, for the purposes of making the question precise, I think form what I have provided, I can get some help.
I will be grateful for your help.
Thanks for the detailed report. My assumption is that the error comes from your tags property. List of String is not a supported type in SQLite. sqflite supports List of int for compatibility reason (for blobs but Uint8List will likely be the only supported type in the future) so the casting error could come from this.
You should try to encode your tags (json or comma separated string) before doing another investigation.
This issue also applies to the author and category fields.
You have to flatten your model. See the supported types help section: https://github.com/tekartik/sqflite/blob/master/sqflite/doc/supported_types.md
Basically int, double, String and Uint8List(blob) are the only types supported. Unfortunately you have to convert your inner List and Map, json being one solution.
But i agree the error reported does not help in finding the issue, that could definitely be improved...

How to query last 3 hours in sqflite?

I'm trying to query the last 3 hours of entries from my sqflite database. Here's my current query:
Future<List<Map<String, dynamic>>> queryLastThreeHours() async {
Database db = await instance.database;
return await db.query(table, where: '$columnDate = ?', whereArgs: ['now', '-3 hours']);
}
For more context, here's the complete code for the database_helper.dart:
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';
static final columnColour = 'colour';
static final columnDate = 'date';
// 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,
$columnColour TEXT NOT NULL,
$columnDate 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<int> queryRowCount() async {
Database db = await instance.database;
return Sqflite.firstIntValue(await db.rawQuery('SELECT COUNT(*) FROM $table'));
}
// 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: '$columnColour = ?', whereArgs: ['Omnivore']);
}
Future<List<Map<String, dynamic>>> queryLastThreeHours() async {
Database db = await instance.database;
return await db.query(table, where: '$columnDate = ?', whereArgs: ['now', '-3 hours']);
}
}
Any help would be greatly appreciated. I've tried to work it out using Sqlite SELECT * for Last 7 days and How to get Last 3 hours data from SQLite, but still haven't figured it out.
Thank you very much in advance!
Jason

Flutter SQFLite create multiple tables at once

I'm using the code below and want to know how this database function can be altered so that it creates two separate tables at once:
static Future<Database> database() async {
final dbPath = await sql.getDatabasesPath();
return sql.openDatabase(path.join(dbPath, 'mydatabase.db'), onCreate: (db, version) {
return db.execute('CREATE TABLE mytable(date TEXT PRIMARY KEY, value DOUBLE)');
}, version: 1);
}
I managed to solve it myself like this:
static Future<Database> database() async {
final dbPath = await sql.getDatabasesPath();
return sql.openDatabase(path.join(dbPath, 'mydatabase.db'), onCreate: (db, version) => _createDb(db), version: 1);
}
static void _createDb(Database db) {
db.execute('CREATE TABLE mytable(date TEXT PRIMARY KEY, value DOUBLE)');
db.execute('CREATE TABLE mytableb(date TEXT PRIMARY KEY, value DOUBLE)');
}
The reason it wasn't working was because after deleting the original database I needed to restart the simulator from cold for it to take effect.

Resources