I'm trying to create a new user table on existing database but sqflite keep showing the error of "no such table Exception" and it executes only one table . I tried changing database name also but nothing worked.
Here is my DBconnector Code:
class DBConnector {
Future<Database> setDatabase() async {
var directory = await getApplicationDocumentsDirectory();
var path = join(directory.path, 'sddssd.db');
var database =
await openDatabase(path, version:1, onCreate: _createDatabase);
return database;
}
Future<void> _createDatabase(Database database, int version) async {
String questionTableName = QuestionModel.KEY_QUESTION_TABLE_NAME;
String userTableName = UserModel.KEY_USER_TABLE_NAME;
String quesTableSql =
"CREATE TABLE IF NOT EXISTS $questionTableName (id INTEGER PRIMARY KEY,question VARCHAR(200),answer VARCHAR(200));";
String userTableSql =
"""CREATE TABLE IF NOT EXISTS $userTableName (uid INTEGER PRIMARY KEY,name TEXT,email TEXT,password TEXT);""";
await database.execute(quesTableSql);
await database.execute(userTableSql);
}
}
Error :
Exception has occurred.
SqfliteDatabaseException (DatabaseException(no such table: User (code 1 SQLITE_ERROR): , while compiling: INSERT INTO User (uid, name, email, password) VALUES (NULL, ?, ?, ?)) sql 'INSERT INTO User (uid, name, email, password) VALUES (NULL, ?, ?, ?)' args [f, e, s]})
String quesTableSql = """CREATE TABLE IF NOT EXISTS $userTableName
(
uid INTEGER PRIMARY KEY,
name TEXT,
email TEXT,
password TEXT
""");
I solved this , the thing is onCreate callback will get executed only one time when you load the application after that no changes will get updated unless u use migration .
So i created a seperate function for creating Table and got it working by making the instance of that class and call the create Table method.
Related
I am doing database migrations using GORM. So I define structs and run them through GORM's AutoMigrate function.
type Person struct {
ID string `gorm:"type:varchar(36);primary_key"`
}
err := db.Table("persons").AutoMigrate(&Person{}).Error
type Address struct {
ID string `gorm:"type:varchar(36);primary_key"`
PersonID string `gorm:"column:person_id;type:varchar(36);NOT NULL"`
}
err = db.AutoMigrate(&Address{}).Error
err = db.Model(&Address{}).AddForeignKey("person_id", "persons(id)", "NO ACTION", "CASCADE").Error
type Contact struct {
ID string `gorm:"type:varchar(36);primary_key"`
AddressID null.String `gorm:"column:address_id;type:varchar(36);NOT NULL"`
PersonID string `gorm:"column:person_id;type:varchar(36);NOT NULL"`
}
err = db.AutoMigrate(&Contact{}).Error
err = db.Model(&Contact{}).AddForeignKey("address_id", "addresses(id)", "NO ACTION", "CASCADE").Error
err = db.Model(&Contact{}).AddForeignKey("person_id", "persons(id)", "NO ACTION", "CASCADE").Error
In the above code, which ever is the second call to the AddForeignKey function on Contacts table is giving error :
mssql: Could not create constraint or index. See previous errors.
Even if I move person_id foreign key above address_id foreign key, then address_id foreign key fails.
I am running MS-SQL server using latest docker container setup(microsoft/mssql-server-linux:latest). Is this something regarding naming of constraint. If yes, then how can we set using GORM? Everything works fine with My-SQL.
It would be really helpful if I get a solution. I cannot run raw queries. Migrations have to be done using GORM only.
Thank You
Multiple foreignkeys can't have 'no action', 'cascade' on the same table. If u use no action, no action u can but u have to handle deletion and updating your self. What I usually do is turn on logmode and copy paste the log sql statement into SQL. This will give u a more clear error.
I have 2 databases. One for folders and one for notes.
The folder database contains a title and json String of a list of id's
The id's are supposed to represent the second database of notes.
Basically folders needs to contain a list of notes and this is the best way I found so far. My problem is that when I create a new note and insert it into the database, I'm not sure how to get the id of the new note back.
If I set the id when I create the note then all notes will have the same id.
If I don't set the id then calling note.id returns null.
Based on my create function the Note's id should set itself (id INTEGER PRIMARY KEY AUTOINCREMENT)
My idea is that when creating the new Note I would somehow return the int id so that I could easily insert it into the folder. Here's what I have so far.
void addNewNote(Note note) async {
var db_connection = await db;
String query =
'INSERT INTO Note(title, content, date_created, date_last_edited) VALUES(\'${note.title}\', \'${note.content}\', \'${note.date_created}\', \'${note.date_last_edited}\')';
await db_connection.transaction((transaction) async {
return await transaction.rawInsert(query);
});
}
The inserted id is also returned from the db.insert() helper method, as the signature
Future<int> insert(String table, Map<String, dynamic> values,
{String nullColumnHack, ConflictAlgorithm conflictAlgorithm})
describes. Example:
final db = await getDb();
final insertedId = await db.insert(
todosTableName,
todo.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
print('insertedId: $insertedId');
You should be able to get the id from the rawInsert like so:
final noteId = await transaction.rawInsert(query);
according to the docs: https://pub.dev/packages/sqflite#raw-sql-queries
Instead of storing a string list of ids on the folders table you can also try store folder_id on the notes table as a foreign key:
https://sqlite.org/foreignkeys.html
Im building and app with flutter that uses SQLite database. I have created first table using this piece of code:
void _createDb(Database db, int newVersion) async {
await db.execute('''CREATE TABLE cards (id_card INTEGER PRIMARY KEY,
color TEXT, type TEXT, rarity TEXT, name TEXT UNIQUE, goldCost INTEGER,
manaCost INTEGER, armor INTEGER, attack INTEGER, health INTEGER, description TEXT)''');
}
Table gets created and I can access it without problems.
Unfortunately I cannot include more than 1 table that i just created. I tried adding another SQL CREATE TABLE clause in the same method, and repeating method db.execute with a different SQL clause just in the next line.
I'm mimicing code from this tutorial: https://www.youtube.com/watch?v=xke5_yGL0uk
How to add another table within the same database?
You can just combine multiple db.execute calls for exampple
await db.execute('''
create table $reminderTable (
$columnReminderId integer primary key autoincrement,
$columnReminderCarId integer not null,
$columnReminderName text not null,
$columnReminderNotifyMileage integer not null,
$columnReminderEndMileage integer not null
)''');
await db.execute('''
create table $carTable (
$columnCarId integer primary key autoincrement,
$columnCarTitle text not null
)''');
yes you can do it
void _createDb(Database db, int newVersion) async {
await db.execute('''
create table $carTable (
$columnCarId integer primary key autoincrement,
$columnCarTitle text not null
)''');
await db.execute('''
create table $userTable(
$userId integer primary key autoincrement,
$name text not null
)''');
}
but to speed up the process, let's assume we have 10 tables, you could use the batch this way
void _createDb(Database db, int newVersion) async {
Batch batch = db.batch();
batch.execute("Your query-> Create table if not exists");
batch.execute("Your query->Create table if not exists");
List<dynamic> res = await batch.commit();
//Insert your controls
}
You can use a .sql file that contains your DB script.
First,add the script file to assets.
Then, import the following packages:
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:flutter/services.dart' show rootBundle;
finally, use the following code
void _createDb() async
{
final database = openDatabase( join( await getDatabasesPath(), 'mydb.db'),
onCreate: (db, version) async
{
// call database script that is saved in a file in assets
String script = await rootBundle.loadString("assets\\db\\script.sql");
List<String> scripts = script.split(";");
scripts.forEach((v)
{
if(v.isNotEmpty )
{
print(v.trim());
db.execute(v.trim());
}
});
},
version: 1,
);
}
Change the name of the DB file. This will 'reset' your DB and creation will work.
e.g:
final dabasesPath = await getDatabasesPath();
final path = join(dabasesPath, "newName2.db");
In openDatabase(path, onCreate, version)
use one more optional parameter "onUpgrade" and define the dropping and again creating table scripts. and also upgrade (increase) the parameter version by one.
----- Code snippet ------
openDatabase(path, onCreate:_createDb, onUpgrade: onUpgrade,version:_DB_VERSION);
...
...
_onUpgrade( Database db, int oldVersion, int newVersion ) async {
Batch batch = db.batch();
// drop first
batch.execute("DROP TABLE IF EXISTS $_TABLE_3 ;");
batch.execute("DROP TABLE IF EXISTS $_TABLE_2 ;");
batch.execute("DROP TABLE IF EXISTS $_TABLE_1 ;");
// then create again
batch.execute("CREATE TABLE $TABLE_1 ...... ");
batch.execute("CREATE TABLE $TABLE_2 ...... ");
batch.execute("CREATE TABLE $TABLE_3 ...... ");
List<dynamic> result = await batch.commit();
}
Note: Each and every time when you will create or change the structure of some table(s), you will have to increase database version in openDatabase() method. so that the upgradation will be called, otherwise it will not be called.
Hard to say without seeing your openDatabase call and whether the database exists before or not. One of my guess is that you are still using the same database version. Once onCreate has been called it will never be called again. You should try to bump your database version and add the new table in on onUpgrade
you can use db.execute for creation of multiple tables under single database.
Future _createDB(Database db, int version) async {
await db.execute('CREATE TABLE users(userId INTEGER PRIMARY KEY, userName TEXT NOT NULL)');
await db.execute('CREATE TABLE tasks(taskId INTEGER PRIMARY KEY, userId INTEGER, task TEXT NOT NULL, status BOOL NOT NULL)');
}
I am running executing raw sql to delete some records that I added for the test. If I run the same query in management studio it works fine but when I run that query EF Core 2.0 it throws below error
System.Data.SqlClient.SqlException: 'Conversion failed when converting the nvarchar value '1,2' to data type int.'
Code
var idList = await Context.User.ToListAsync();
var ids = string.Join(",",idList.Select(x=>x.Id));
await _context.Database.ExecuteSqlCommandAsync($"Delete from User where Id in ({ids}) and RoleId = {contact.RoleId}");
Query executing
Delete from sale.WatchList where OfferId in (1,2) and UserId = 9
Could anybody please advise on what wrong with the above code.
Thanks
EF Core will transform interpolated strings into queries with parameters to create reusable queries and protect against SQL Injection vulnerabilities. See: Raw SQL Queries - EF Core - Passing Parameters
So
$"Delete from User where Id in ({ids}) and RoleId = {contact.RoleId}"
is transformed into
Delete from User where Id in (#ids) and RoleId = #RoleId
With SqlParameters bound.
If that's not what you want, just build the SQL Query on a previous line.
This will not work. You have to write dynamic query. Please try like below one
var idList = await _dataContext.User.ToListAsync();
var ids = string.Join(",", idList.Select(x => x.Id));
await _dataContext.Database.ExecuteSqlCommandAsync($"execute('Delete from User where Id in ({ids}) and RoleId = {contact.RoleId}')");
although accepted answer does work, it creates lot of warnings so for now I am using what #Abu Zafor suggested with small change/fix
await _dataContext.Database.ExecuteSqlCommandAsync($"execute('Delete from User where Id in ({ids}) and RoleId = {contact.RoleId}')",ids,contact.RoleId);
I successfully created the Database and inserted a row however I cannot Query it for some reason. My Droid crashes everytime.
// Create a new row of values to insert.
ContentValues newValues = new ContentValues();
// Assign values for each row.
newValues.put("value", "kunjan");
// Insert the row into your table
myDatabase.insert(DATABASE_TABLE, null, newValues);
String[] result_columns = new String[] { "value" };
// I GET AN EXCEPTION HERE
Cursor allRows = myDatabase.query(true, DATABASE_TABLE, result_columns, null, null,
null, null, null, null);
if (allRows.moveToFirst()) {
String value = allRows.getString(0);
TextView foo = (TextView) findViewById(R.id.TextView01);
foo.setText(value);
}
allRows.close();
myDatabase.close();
I get this exception
no such column: value: , while compiling: SELECT DISTINCT value FROM mainTable
I think you are creating table with only one column(value) and you are trying to read the column-1 instead of column-0 from the cursor. If that still not helps, please add try-catch block and capture the logs
String value = allRows.getString(0);
Some of the problems with the original post
Creating a table that has already been created. I wrote "if not exists" in the "create table" instruction.
Not handling Exceptions properly. I got a lot of exceptions in the creation of the table, quering it etc. I sorrounded all these operations with try-catch
Using hard coded values for Column names - This made it harder to verify if I was querying the column that I had created.