How can get SQLite date in flutter?
In my project, I had used the sqlite and I had written the code, but I don't know how can get data when I need to read it.
class DatabaseHelper {
DatabaseHelper._privateConstructor();
static final DatabaseHelper instance = DatabaseHelper._privateConstructor();
static Database? _database;
Future<Database> get database async => _database ??= await _initDatabase();
Future<Database> _initDatabase() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, 'user.db');
return await openDatabase(path, version: 1, onCreate: _onCreate);
}
Future _onCreate(Database db, int version) async {
await db
.execute('''CREATE TABLE USER (id INTEGER PRIMARY KEY, badge TEXT)''');
}
Future<List<Grocery>> getGroceries() async {
Database db = await instance.database;
var groceries = await db.query('USER', orderBy: 'badge');
List<Grocery> groceryList = groceries.isNotEmpty
? groceries.map((e) => Grocery.fromMap(e)).toList()
: [];
return groceryList;
}
}
I had written this code and I need to got the badge data. How could I can got it?
The bage data only has one date, it was just recode the notification badge. so anytime was update it.
You can get the data calling the getGroceries() method in initState or using the FutureBuilder widget in flutter.
Related
I'm a beginner in flutter, i want to use SQlite database using sqflite package in my Flutter App, when I declare the _database variable with this syntax static Database _database; i got a compilation error saying that i must initialize _database, and when i use this syntax static Database? _database;, i have a compilation error under return _database saying A value of type 'Database?' can't be returned from the function 'database' because it has a return type of 'Future<Database>'. and when i put static late Database _database; i have an error in execution saying Error: LateInitializationError: Field '_database' has not been initialized.
my code is
class AnnonceDataBase {
AnnonceDataBase._();
static final AnnonceDataBase instance = AnnonceDataBase._();
static Database _database;
Future<Database> get database async {
if (_database != null) return _database;
_database = await initDB();
return _database;
}
}
I have modified it a bit but it works for you using a singleton to maintain the state of the database
class AnnonceDataBase {
AnnonceDataBase._();
static final AnnonceDataBase _instance = AnnonceDataBase._();
static Database? _database;
factory AnnonceDataBase() => _instance;
Future<Database> get database async {
if (_database != null) return _database!;
_database = await initDB();
return _database!;
}
Future<Database> initDB() async {
String table1 = "CREATE TABLE IF NOT EXISTS table1(id INTEGER PRIMARY KEY,key TEXT NOT NULL UNIQUE,name TEXT,phone NUMERIC)";
String table2 = "CREATE TABLE IF NOT EXISTS table2(id INTEGER PRIMARY KEY,key TEXT NOT NULL UNIQUE,name TEXT,phone NUMERIC)";
String path = await getDatabasesPath();
// Open the database and save the reference.
final Future<Database> database = openDatabase(
// Set the path to the database. Note: Using the `join` function of the
// plugin `path` is best practice to ensure the path is correct
// built for each platform.
p.join(path, 'admin.db'),
// When the database is first created, create a table to store data
onCreate: (db, version) {
db.execute(table1);
return db.execute(table2);
},
// Set the version. This runs the onCreate function and provides a
// path to perform updates and downgrades on the database.
version: 1,
);
return database;
}
}
You can use it like this
#override
void initState() {
AnnonceDataBase._instance.database; //Initialize when loading the application or in the singleton
super.initState();
}
Create a record
Future<void> addData() async {
Database database = AnnonceDataBase._database!;
database.transaction((txn) async {
await txn.rawInsert('INSERT INTO table1(id,key,name,phone) VALUES(?,?,?,?)', ["1", DateTime.now().toString(), "name", "+5555555"]);
});
}
Read all records
Future<void> readData() async {
Database database = AnnonceDataBase._database!;
List<Map> data = await database.rawQuery("SELECT * FROM table1");
debugPrint("data: $data");
}
I am using flutter in vs code. I have got this error when I am connecting to sqflite database.
I have added sqflite,path plugin in pubspec.yaml file. I have tried
flutter clean
flutter run command too but nothing worked.
This is my Database helper method
final databaseName = "notes.db";
final tableName = "notes";
DatabaseHelper._();
static final DatabaseHelper db = DatabaseHelper._();
static Database _database;
final fieldMap = {
"id": "INTEGER PRIMARY KEY AUTOINCREMENT",
"title": "TEXT",
"body": "TEXT",
"creation_date": "DATE",
};
Future<Database> get database async {
if (_database != null) return _database;
_database = await initDB();
return _database;
}
initDB() async {
var path = await getDatabasesPath();
var dbPath = join(path, 'notes.db');
// ignore: argument_type_not_assignable
Database dbConnection = await openDatabase(dbPath, version: 1,
onCreate: (Database db, int version) async {
print("executing create query from onCreate callback");
await db.execute(_buildCreateQuery());
});
await dbConnection.execute(_buildCreateQuery());
_buildCreateQuery();
return dbConnection;
}
The values are not getting stored in sqflite databse. It returns null. So what should I do?
I have a .db file in the Documents on the device. It has a particular Sqlite database stored on it. How would I import that database file and replace the old one in Flutter? It always has the same name and the same destination in Documents. Here is the code in the DbHelper.dart that initializes the original database, what I'm looking for is replacing that one with the db file I have of another database in the Documents.
DatabaseProvider._();
static final DatabaseProvider db = DatabaseProvider._();
Database _database;
Future<Database> get database async {
print("database getter called");
if (_database != null) {
return _database;
}
_database = await createDatabase();
return _database;
}
Future<Database> createDatabase() async {
String dbPath = await getDatabasesPath();
return await openDatabase(
join(dbPath, 'oldDB.db'),
version: 1,
onCreate: (Database database, int version) async {
print("Creating table");
await database.execute(
"CREATE TABLE $TABLE_PERSON ("
"$COLUMN_ID INTEGER PRIMARY KEY,"
")",
);}
On another page I have a button, for example IMPORT where I would need to have a function that imports the new database file from Documents and replace the old one and persist. How would I go around doing that the most simple way?
This is function that I thought would work, but I am getting asynchronous errors and a lot more weird errors:
class DbHelper {
Future initDb() async {
final dbPath = await ExtStorage.getExternalStoragePublicDirectory(
ExtStorage.DIRECTORY_DOCUMENTS);
final path = join(dbPath, 'backup.db');
final exist = await databaseExists(path);
if (exist) {
print('db imported');
await openDatabase(path);
}
await openDatabase(path);
}
}
I have stored my phones call list into a data table. I want to store only new call list data into this data table. It means, only new data will be saved and existing data will be skipped.
Please tell me with example.
Here is my code:
this is the Database Helper
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 columnNumber = 'number';
static final columnType = 'type';
static final columnDate = 'date';
static final columnDuration = 'duration';
// 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 getExternalStorageDirectory();
String path = join(documentsDirectory.path, _databaseName);
await deleteDatabase(path);
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,
$columnNumber INTEGER,
$columnType TEXT,
$columnDate DATETIME,
$columnDuration INTEGER
)
''');
}
// 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, {ConflictAlgorithm conflictAlgorithm = ConflictAlgorithm.replace}) async {
Database db = await instance.database;
return await db.insert(table, row, conflictAlgorithm: conflictAlgorithm);
}
// 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]);
}
}
This is the main file. I have added here only the Database insertion method. home.dart
...
Future callLogDB() async {
Iterable<CallLogEntry> cLog = await CallLog.get();
final dbHelper = DatabaseHelper.instance;
cLog.forEach((log) async {
// row to insert
Map<String, dynamic> row = {
DatabaseHelper.columnName: '${log.name}',
DatabaseHelper.columnNumber: '${log.number}',
DatabaseHelper.columnType: '${log.callType}',
DatabaseHelper.columnDate:
'${DateTime.fromMillisecondsSinceEpoch(log.timestamp)}',
DatabaseHelper.columnDuration: '${log.duration}'
};
await dbHelper.insert(row, conflictAlgorithm: ConflictAlgorithm.replace);
print('CallLog:: $row');
});
return cLog;
}
...
What's the problem with my code?
there are several ways to do this, and the one I will offer are not the best or the nicest ones, but hope that they will help
1) Simply write all your data to table
You can just insert all your data to the table setting the ConflictAlgorithm to replace or ignore
db.insert(table, data, conflictAlgorithm: ConflictAlgorithm.replace);
This will replace/ignore same entries
2) Query, compare, replace
This is a less 'elegant' solution, you can first query all your data from table
db.query(table, columns: availableColumns, where: 'columnToQueryBy = ?', whereArgs: [neededValue]);
Then compare to the data you have
Then write using db.insert() as above
I think that in your case the first option suits better, this example pretty much covers most things that might help you
Hope it helps!
WHAT ABOUT Read Data from Sqflite and Show in datatable?
I'm trying to perform CRUD operations on Flutter, using the sqflite library. Online resources point towards a bunch of ways to go about this. Here is my implementation:
class SqlManager {
static const String tname = 'table1';
static const String dname = 'database.db';
Future<Database> db;
initDB() async {
Directory path = await getApplicationDocumentsDirectory();
db = openDatabase(join(path.path, dname), version: 1, onCreate: (db, version) {
return db.execute(
'CREATE TABLE $tname (id INTEGER PRIMARY KEY, name TEXT, type TEXT, time1 INTEGER, time2 INTEGER, imp INTEGER, urg INTEGER)');
});
}
Future<void> writing(Task task) async {
print("called");
final Database DB = await db;
await DB.insert(
tname,
task.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
print("Execution completed");
}
Future<List<Task>> reading() async {
Database DB = await db;
List<Map<String, dynamic>> maps = await DB.query(tname);
return List.generate(maps.length, (i) {
return Task.fromMap(maps[i]);
});
}
}
Whenever I attempt to call any of these functions, I hit upon a NoSuchMethodError, thrown by the variable 'DB' inside one of these functions. Any help is appreciated, thanks!
Whenever I attempt to call any of these functions, I hit upon a NoSuchMethodError, thrown by the variable 'DB' inside one of these functions. Any help is appreciated, thanks!
It's because you haven't initialized your database by calling the initDB(). So, call it before you call the method using the database. But you'll end with recreating each instance for each call.
The better way is by creating a singleton for your database. Modify your SqlManager to something like this:
class SqlManager {
static const String tname = 'table1';
static const String dname = 'database.db';
// Future<Database> db;
// Make a singleton class
SqlManager._privateConstructor();
static final SqlManager instance = SqlManager._privateConstructor();
// Use a single reference to the db.
static Database _db;
// Use this getter to use the database.
Future<Database> get database async {
if (_db != null) return _database;
// Instantiate db the first time it is accessed
_db = await _initDB();
return _db;
}
// Init the database for the first time.
_initDB() async {
Directory path = await getApplicationDocumentsDirectory();
return await openDatabase(join(path.path, dname), version: 1, onCreate: (db, version) {
return db.execute(
'CREATE TABLE $tname (id INTEGER PRIMARY KEY, name TEXT, type TEXT, time1 INTEGER, time2 INTEGER, imp INTEGER, urg INTEGER)');
});
}
// Then you can use the database getter in another method
Future<List<Task>> reading() async {
Database DB = await instance.database;
List<Map<String, dynamic>> maps = await DB.query(tname);
return List.generate(maps.length, (i) {
return Task.fromMap(maps[i]);
});
}
}