I have a project with a set of classes that are responsible for their respective database tables.
Each table managing class contains CRUD methods that follow the pattern of get connection, run crud operation, close connection:
public class PersonManager {
SQLiteDatabase db;
DbAdapter dbAdapter; //This is a subclass of SQLiteOpenHelper
public void addPerson(Person person)
{
ContentValues contentValues = new ContentValues();
contentValues.put("email", person.email);
contentValues.put("first_name", person.firstName);
db = dbAdapter.getWritableDatabase();
db.insert("person", null, contentValues);
db.close();
}
...other crud/utility methods omitted...
}
Now that I am upgrading my database via onUpgrade(), I run into database locked issues.
The exact error message follows:
CREATE TABLE android_metadata failed
Failed to setLocale() when constructing, closing the database
android.database.sqlite.SQLiteException: database is locked
It appears that onUpgrade is either meant to:
1 run db.execSQL() calls or
2 use helper classes that use onUpgrade()'s SQLiteDatabase rather than their own
It would be much easier to use my table managing classes to migrate data in onUpgrade() than db.execSQL() statements, or rewrite all my CRUD methods to take onUpgrade()'s SQLiteDatabase.
Am I setting up my database access correctly? If the above code follows the correct pattern, what should I do to fix this issue?
Thanks!
Here's your problem:
db = dbAdapter.getWritableDatabase();
When you're in onUpgrade(), you have to use the SQLiteDatabase handle that onUpgrade() provides you. So your solution is to rewrite your addPerson function to take one more argument -- an SQLiteDatabase handle:
public void addPerson(Person person, SQLiteDatabase db) {...}
If you need to call addPerson() from elsewhere in your project, then keep your current addPerson(Person person) function, have it do that
db = dbAdapter.getWritableDatabase()
call, and pass db to your two-argument version of addPerson().
I didn't get any answers, so I asked on a dev hangout.
According to the Android Developer Hangout Team, onUpgrade is only meant for structure alterations, not really for data migration/manipulation.
Related
I'm currently building an app which utilises the SQLite Database in Android, I understand that the tables are set up when overriding "onCreate" in my subclass of SQLiteOpenHelper.
However, I want the database to be created with a set of default information and was wondering where it was conventional to insert this? Should I be doing this with SQL in onCreate, or later on by checking a preference such as "onFirstRun" and using my Helper class to insert some values in an Activity somewhere?
Any helps/tips appreciates, cheers.
I usually add default data on the OnCreate of the class that extends SQLiteHelper like this, because its only does once (unless you uninstall the app) and it is quite clear and easy:
public class XXX extends SQLiteOpenHelper {
String sqlCreate = "CREATE TABLE X (codigo INTEGER, nombre TEXT)";
String sql ="Insert into X ....";
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(sqlCreate);
db.execSQL(sql);
}
It is better to insert default information in onCreate of SQLiteOpenHelper if you haven't released your app already to store. If already released do it in onUpgrade of SQLiteOpenHelper by making the necessary validations. This way all the code related to db stays together and you can manage the upgrade scenarios gracefully.
When there is new data available to my Android application I need to completely remove all current entries in one of the SQLite database tables and replace them all with the new data. What is the best way to do this?
Would it be best to run
DELETE * FROM my_table
or
run a delete query for every row in the database
or run
database.execSQL(DATABASE_DROP_MY_TABLE);
database.execSQL(DATABASE_CREATE_MY_TABLE);
Where DATABASE_DROP_MY_TABLE is SQL to drop the table and DATABASE_CREATE_MY_TABLE is
SQL to create the table again with no entries.
And then following one of these, insert the new data.
Of course there are probably other ways to do this that I have not thought of.
Assuming you're using SQLiteOpenHelper, you can just close db, delete the whole file and recreate the db:
class MyDatabase extends SQLiteOpenHelper {
public static final String DB_NAME = "wat";
public MyDatabase(Context context) {
super(context, DB_NAME, null, CURRENT_VERSION);
}
}
dbHelper.close(); // dbHelper is your MyDatabase instance
context.deleteDatabase(DB_NAME);
SQLiteDatabase db = dbHelper.getWritableDatabase() // will create empty db
Nice thing about this solution is that you won't have to update table resetting code when you add new tables to your schema. It also correctly recreates indexes you might have added.
I wouldn't complicate things, and simply drop the table with DROP TABLE statement. As the doc say:
The SQLite DROP TABLE statement is used to remove a table definition and all associated data, indexes, triggers, constraints and permission specifications for that table.
You would have clean plate, then create the table again and add your new data.
I'm using SQLite in android application and i need to execute some complex insert statement (with subqueries).
I'm found SQLiteStatement very useful for this purpose. It can be compiled and executed many times as insert statement returning autoincremeneted primary key.
Since i'm closing my SQLiteOpenHelper (which closes contained SQLiteDatabase) on Activity#onPause() and re-open it in Activity#onResume() i will get different SQLiteDatabase instances time-by-time.
Should i re-compile query for each SQLiteDatabase instance?
Or i can cache compiled statement in static variable and succesfully use it for different SQLiteDatabase instances?
The source code suggests me that i should (SQLiteStatement contains reference to SQLiteDatabase)... But i'm not sure.
Any help is greatly appreciated.
SQLiteStatement objects are associated with a specific SQLiteDatabase object, and cannot be moved to another one (there is no function for that, and the result of the compilation wouldn't work in any other database anyway).
You have to create new statement objects for your new database object.
Hey guys I am having a some problems with SQLcipher db for android
The documentation is not too descriptive so I could not figure it out.
I am trying to modify the default number of iterations on sqlcipher for android,
I am editing the notecipher app provided as demo app with sqlcipher, and want to increase the kdf_iter to i.e. 5000
By overriding the getWritableDatabase() method in the database helper i enter the pragma value just after the file is open with the password.
I can open and initialize the database, but I cannot re-open the db if I do a database.close() call.
whenever I close the database on the next open() call I get a :
I/Database(807): sqlite returned: error code = 26, msg = file is encrypted or is not a database
E/Database(807): CREATE TABLE android_metadata failed
E/Database(807): Failed to setLocale() when constructing, closing the database
E/Database(807): info.guardianproject.database.sqlcipher.SQLiteException: file is encrypted or is not a database
You'll want to use a SQLiteDatabaseHook object to call the kdf_iter pragma. This will ensure that the pragma is called immediately after the database is opened, but before it is used.
SQLiteDatabaseHook hook = new SQLiteDatabaseHook(){
public void preKey(SQLiteDatabase database){
database.rawExecSQL("PRAGMA kdf_iter = 5000");
}
public void postKey(SQLiteDatabase database){}
}
SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(databasePath, password, null, hook);
#Stephen answer is only partially correct, because according to the documentation:
PRAGMA kdf_iter must be called after PRAGMA key and before the first actual database operation or it will have no effect.
So the line:
database.rawExecSQL("PRAGMA kdf_iter = 5000");
Must be inserted in the postKey() method, and NOT in preKey().
This worked for me.
I'm new to programming. I'm making an Android app and I am at a new hurtle. I am using the SQLiteOpenHelper class to manage my database. Its been great, I am able to create tables, add entries and all that good stuff.
The problem I have is that for one of my tables I want to have an initial 7 entries that keep the same ID and can be replaced by the user. My plan is to use a SQLiteDatabase.replace() method in order to replace these entries. Since I want the entries to be set by me and then edited by the user, that means I want to add entries using the SQLiteOpenHelper class so that these entries are set only when the user installs the app and creates the database. I do not want to make a pre-populated database that I must include in the install package.
My Java skills are god awful so my main question is how do I add entries from inside my SQLiteOpenHelper class? I already know how to add entries in my other classes using the following method that I made:
public long createCategoriesSQLEntry(String name) {
ContentValues cv = new ContentValues();
cv.put(COLUMN_CATEGORIES, name);
return myDatabase.insert(StringCategory_Table, null, cv);
}
Override the onCreate() in the database helper. Like this.
#Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
try{
if(db.isOpen()){
//create tables here
db.execSQL("create table");
db.execSQL("insert row");
db.execSQL("insert row");
}
}
You are database will be installed when for the first time your application is installed. So, you write you data either in file and load it on onCreate method in SQLiteHandling class or just write the data in your java and call it in onCreated method like CyberTengu said.