Should simultaneously having multiple different SQLite Database Versions be considered harmful? - android

I am breaking out each SQLite table's code (including initial construction of the table as well as operations on that table) into separate classes extending SQLiteOpenHelper.
In order to get these tables to be created (that is to say, to get the onCreate() method to be called), I have to increment the DATABASE_VERSION (see my own answer here for the details).
But with this methodology, I end up with different version numbers for each class/table - I had to set the DATABASE_VERSION value for the second table I created to 2, I will have to set the third one to 3, etc.
So I will end up with multiple different version values for the same DATABASE (*.db file). If they are all the same val, the onUpgrade() method does not get called, and thus, the onCreate() method is not called, and thus the new table is not created.
Is this "okay" - having a database with several different simultaneous version numbers?
The only other (reasonable) option I know of is to put all the DB code (covering multiple tables) into a single class that extends SQLiteOpenHelper - is doing so actually the preferred method? IOW, is my separation of the db code into several classes, one for each table, a help or a hindrance?
UPDATE
So this is my non-destructive way (by inserting "IF NOT EXISTS" into the DDL) to gradually add new tables, using, per CommonsWare's advice, just one class that extends SQLiteOpenHelper:
#Override
public void onCreate(SQLiteDatabase db) {
String CONDITIONALLY_CREATE_VENDORS_TABLE = "CREATE TABLE IF NOT EXISTS " +
TABLE_VENDORS + "("
+ COLUMN_ID + " INTEGER PRIMARY KEY," + COLUMN_VENDORID
+ " TEXT," + COLUMN_COMPANYNAME + " TEXT" + ")";
db.execSQL(CONDITIONALLY_CREATE_VENDORS_TABLE);
// add more tables as needed following the pattern above
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//db.execSQL("DROP TABLE IF EXISTS " + TABLE_VENDORS); <= Only need to DROP if the table's structure changes; so comment such a line out for the particular table in that case
onCreate(db);
}
NOTE: Whenever I do add a new table, I have to "up" (increment) the DATABASE_VERSION value, so that onUpgrade()/onCreate() are called.

I am breaking out each SQLite table's code (including initial construction of the table as well as operations on that table) into separate classes extending SQLiteOpenHelper
It is important, for thread safety among other reasons, to have a single instance of SQLiteDatabase that you use consistently. That in turn, will require you to have a single SQLiteOpenHelper class. The exception would be for totally independent database files (one SQLiteHelper per database), but that's not usually needed.
Is this "okay" - having a database with several different simultaneous version numbers?
That is not "okay" at all. The highest number wins.
The only other (reasonable) option I know of is to put all the DB code (covering multiple tables) into a single class that extends SQLiteOpenHelper - is doing so actually the preferred method? IOW, is my separation of the db code into several classes, one for each table, a help or a hindrance?
Breaking out "the db code into several classes, one for each table" is not necessarily a problem. What is a problem is having them be independent subclasses of SQLiteOpenHelper.
Let's say that you want these classes not merely to handle table creation and upgrades, but also other CRUD operations related to the table. Having a dedicated class for that is fine. However, the table creation and upgrade logic needs to be driven by a single SQLiteOpenHelper class. Simply have onCreate() and onUpgrade() on your SQLiteOpenHelper delegate the actual work to the per-table classes. This way, you get your code organization, without having multiple SQLiteOpenHelper classes.

Related

Creating new tables automatically vs Giant table

Im receiving throught BLE data stored in an SD Card. This data is organized in multiple text files, with each file corresponding to a date.
When receiving this data on android i want to save it on a SQlite database.
Thought about using the same logic, creating a table for each day. My question is if its possible to automatically create tables depending on the number of days that is going to be transfered. After some research i found how to add new tables using the onUpgrade method and changing the database version, but this seems only possible by changing the database version manually.
Another option would be by creating a single table for all the data, and add the date as a column.
Any feedback is valuable!
Typically you would use a single table with the date as a column.
It would be possible to dynamically create tables, if they don't exist outside of the onUpgrade method. For each date/file you could, when receiving the file and before loading/inserting the data, either :-
use CREATE TABLE IF NOT EXISTS the_table_with_a_name_that_relates_to_the_date (the_column_definitions)
i.e. if the table exists then the above is effectively a NOOP.
use something like (the below assumes this method is in the DatabaseHelper)
:-
public bolean checkAndAddTable(String tableName) {
boolean rv = false;
SQLiteDatabase = this.getWriteableDatabase();
Cursor csr = db.query("sqlite_master",null,"name=? AND type='table'",new String[]{tableName},null,null,null);
if (csr.getCount() < 1) {
db.execSQL("CREATE TABLE IF NOT EXISTS " + tableName + "(......SQL TO CREATE THE COLUMN DEFINITIONS......)");
rv = true;
}
csr.close();
return rv;
}
Note the code is in-principle code ans has not been run or tested and my therefore have some errors.
However, extracting the data from multiple tables would/should need to check if the table exists, to see if data can be extracted which would incur additional processing/complications (e.g. what to do if it doesn't exist).

how to make changes to one table in onupgrade method of database of five tables ignoring the rest in oncreate method

I have five tables in my sqlite db, the five tables are created in oncreate method if I make changes to one table in upgrade method based on the previous db version when I launched the app the changes are made I can see through my logcat but it calls oncreate method and say the 4 tables already exist. How can I handle this error?
public void onUpgrade(SQLiteDatabase database, int version_old, int current_version) {
if (version_old < 3) {
database.execSQL(queryFive);
}
on onCreate I have statements that creates table initially which is then called again after onUpgrade and triggering the error they already exist. How can I handle this? Thanks.
If you make changes in one table, you should increment the DATABASE_VERSION = 1,2,3 and so on.
Whenever changes are done in database, you should first drop (delete) all table and create them again.
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); // drop table(s),if you have five tables , drop all five
onCreate(db); // this will create all tables again
}
Update : in case of not loosing old data of other tables
You need an abstract class that implements the upgrade process described here. Then you extend this abstract class for each of your tables. In your abstract class you must store you tables in a way(list, hardcoded) so when the onUpgrade fires you iterate over the table items and for each table item you do the described steps. They will be self upgraded, keeping all their existing details. Please note that the onUpgrade event fires only once per database, that's why you need to iterate over all your tables to do the upgrade of all of them. You maintain only 1 version number over all the database.
beginTransaction
run a table creation with if not exists (we are doing an upgrade, so the table might not exists yet, it will fail alter and drop)
put in a list the existing columns List<String> columns = DBUtils.GetColumns(db, TableName);
backup table (ALTER table " + TableName + " RENAME TO 'temp_" + TableName)
create new table (the newest table creation schema)
get the intersection with the new columns, this time columns taken from the upgraded table (columns.retainAll(DBUtils.GetColumns(db, TableName));)
restore data (String cols = StringUtils.join(columns, ",");
db.execSQL(String.format(
"INSERT INTO %s (%s) SELECT %s from temp_%s",
TableName, cols, cols, TableName));
)
remove backup table (DROP table 'temp_" + TableName)
setTransactionSuccessful
other than that, there is not way you can achieve this. unless, you can create separate db file for each table.

why we need to onUpgrade(); method in SQLiteOpenHelper class

I m following this tutorial.http://www.androidhive.info/2011/11/android-sqlite-database-tutorial/
can any body please make me clear this chunk of code.
// Creating Tables
#Override
public void onCreate(SQLiteDatabase db) {
String CREATE_CONTACTS_TABLE = "CREATE TABLE " + TABLE_CONTACTS + "("
+ KEY_ID + " INTEGER PRIMARY KEY," + KEY_NAME + " TEXT,"
+ KEY_PH_NO + " TEXT" + ")";
db.execSQL(CREATE_CONTACTS_TABLE);
}
// Upgrading database
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + TABLE_CONTACTS);
// Create tables again
onCreate(db);
}
Questions
What is the purpose of onUpgrade(); method?
When it is Called? as docs says this is Called when the database needs to be upgraded what does it means by upgrading the database?
Important
why we drop the table in this method and recreate?
Thanks in advance.
onUpgrade is basically for handling new db changes(could be new columns addition,table addition) for any new version of your app.
Droping the table is not always necessary in onUpgrade it all depends on what your use case is. If the requirment is to not to persists the data from your older version of app then drop should help,but if its like changing schema then it should only have alter scripts.
Upgrade means changes have been made to the database schema(version numbers are different) and it needs to be upgraded. Dropping the table and recreating is one way to do that. You could also issue "alter table" statements.
When you open your database it checks the version number and whether or not it exists. You can just "upgrade" your database rather than creating it new.
A good tutorial: http://www.vogella.com/articles/AndroidSQLite/article.html
This method is called when you update your database version. It drops the existing tables and creates it again when onCreate method is called again.
Replying to your 4 questions:
1) The purpose of onUpgrade is to manage a new database structure. You could start you app with simple features, then you need for instance to add a new column, so you need to increase the version of your database from 1 to 2 and in onUpgrade
give the instruction to add a new column, so that if the user update the app, the new column become added.
2) onUpgrade is called when you have a new version of your database and you incremented the int number in the super method( here is 1, so you eventually change it to 2)
public static class DatabaseHelper extends SQLiteOpenHelper{
DatabaseHelper(Context context){
super (context,DATABASE_NAME,null,1);
}
3) Please see above regarding what does it means to update the db
4) We Drop the table and recreate, because to modify the table (example for adding a new column that fits a new feature) a logic way to proceed could be, before to "destroy"/DROP the table and then create a new one with all the data. But this can be not the way to go although recreating the data could mean that the id numbers will be consecutive( usually are not consecutive: you could have 1, 2, and..4 because 3 has been deleted), hence dropping and then creating the table again, and eventually loading the previous data you could have this id consistency.
Sometimes you may want to use ALTER instead of DROP. Why? Usually because using DROP the user loses the content already has in the database, then if you want to learn more about Best practices and more complex real life scenarios please have a look at this amazing reply

How to update an SQLite Database and NOT lose all existing data?

I'm adding a table to my app's SQLite DB. All my syntax there is fine, not the issue. But I'm having some trouble getting the new table to be created properly. I added the new table....
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DATABASE_CREATE);
db.execSQL(CREATE_REQUESTS);
db.execSQL(CREATE_OVERRIDE);
}
My on create method. I have 3 tables. When I updated the version number, I got an error saying "table requests (referring to CREATE_REQUESTS) has already been created." A look at my onUpgrade method...
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS contacts");
onCreate(db);
}
Led me to understand that the line db.execSQL("DROP TABLE IF EXISTS contacts"), which refers to my DATABASE_CREATE table in the onCreate method, is used to drop the old table, then the next line, onCreate(db); recreates it. I did not add requests into that execSQL line, which is what caused the error. Here is the issue: I would rather not lose the data in the two tables I already have. Is there a way to add a table like I am trying to do, and not lose all the old data? Thanks.
You can do anything you want in onUpgrade. You can use ALTER to add new columns to your table.
Worst case, if your schema is completely and entirely different, you'll have to create the new table, populate it using data from the old table, and then delete the old table.
In any case, onUpgrade was designed to allow for a smooth upgrade without any loss of data. It's just up to you to implement it properly.
if DB version : 6
Ex : There is a table with 5 columns
When you upgrade to : 7 ( I am adding 1 new column in the 3 tables)
1. We need to add the columns when creating a table
2. onUpgrade method:
if (oldVersion < 7)
{
db.execSQL(DATABASE_ALTER_ADD_PAPER_PAID);
db.execSQL(DATABASE_ALTER_LAST_UPLOADED);
db.execSQL(DATABASE_ALTER_PAPER_LABEL);
}
Where : "DATABASE_ALTER_ADD_PAPER_PAID" is query.
EX: public static final String DATABASE_ALTER_ADD_PAPER_PAID = "ALTER TABLE "
+ TableConstants.MY_PAPERS_TABLE + " ADD COLUMN " + COLUMN_PAPER_PAID + " TEXT;";
After above two operation it will works fine for the fresh install user and app upgrade user

Does an Android database get completely removed and recreated then updating an app?

I have an app that uses a database. At startup I check to see if my tables are missing and if so I create them. Works great.
I've noticed that if I "adb uninstall" then the next time I run my app the tables are created again (this is what I need), but what about when updating through the marketplace?
I'm in the process of releasing an update, and I've made major changes to the tables. I'd like it if the tables were completely wiped and re-created, in fact my app needs this to happen. If someone updates and has the old tables then there will be a force close.
Does anyone know the specifics of this scenario?
My tables are only for lookup, I store no user data so I dont really care about losing data on the updates.
Of course I know an option is to use some type of "version" table and check to see if I need to manually drop and create, but I was wondering if that was even needed.
Thanks.
On an update the tables are left alone. I'm going to assume you have implemented a subclass of SQLiteOpenHelper to explain this. The way Android is able to handle version changes is through the use of onUpgrade in the SQLiteOpenHelper class. This method is called from SQLiteOpenHelpers constructor if the DB version is older than the version the app expects. From inside onUpgrade is where you are going to drop your old tables and create the new ones.
onUpgrade (SQLiteDatabase db, int oldVersion, int newVersion){
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
//we can change this to perform different behaviors
db.execSQL("DROP TABLE IF EXISTS "+MYDB.TABLE_NAME);
onCreate(db);
}
It is important to note the way Android tells if you are using a new DB version.
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
That field DATABASE_VERSION is used, so you should use a final static int member as part of your DB implementation.
Hope that helps, leave me a comment if you have questions.

Categories

Resources