sql onUpgrade for new users - android

This is a trivial question, but I am afraid to put in production wrong code and that testing in devices/emulator could lead to cache problems that do not mirror the reality.
My assumptions:
As well documented on SO, I need to add a column to my DB, I decided to use ALTER table ADD column
in onUpgrade(), and to change the version in the constructor of the DB from 1 to 2, so that the constructor will recognize that is running the new version and the onUpgrade() function should be triggered.
My 2 problems:
1) MOST IMPORTANT. Let's assume old users will upgrade successfully the db, but what happens with new users that still have to create even the first row of the DB, will they be directed to OnCreate() and not onUpgrade() because version is 2, or to on OnCreate() and then onUpgrade(), or almost impossible directly in OnUpgrade() skipping for some API reason even onCreate()?
In other terms do I need to update the new column changing the old onCreate() comprehending the new added column?
2) in onUpgrade() after
ALTER <table> ADD <column>
logically do I have to CREATE a new table right? Should I call onCreate() that as an updated Table( ex. instead of the original 4 column, now has 5 columns)?

When getWritableDatabase() is called, it checks the database file. If it does not exist, onCreate is called. If it does exist, but has a wrong version, onUpgrade is called.
So onCreate is responsible for creating the database schema of the current version, while onUpgrade is responsible for changing some existing database to have the schema of the current version.
You could share code between onCreate and onUpgrade, but calling that code is your own responsibility; the framework will not check the version again after the onXxx callback has returned.

Related

Adding new table to sqlite

For SQLiteOpenHelper, if I add a new table inside onCreate do I have to do anything inside onUpgrade? I am adding a completely new table. I believe I have to change the version number but that onUpgrade should remain empty. Is that correct?
If you want existing installs of the app to add this new table, then yes, you must increase the version and provide a suitable onUpgrade() implementation, as well as adding the table in onCreate() (which you stated you have already done).
An empty onUpgrade() implementation is not sufficient; it has to actually do something. Some people drop all tables and just call onCreate() directly, but this obviously doesn't work well if you are trying to keep existing data. I usually use the fall-through switch idiom, so that if a user is more than one version behind (e.g. you publish a version 3 and a user is still on version 1) they will go through all the necessary upgrades sequentially:
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion) {
case 1:
db.execSQL("CREATE TABLE " + ...);
// no break statement, so case 2 will execute after this.
case 2:
// more execSQL(), etc
}
}
onCreate() will not be called if a user already has installed your app previously. So you need to create the new table in onUpgrade(), too. Be sure to increase the version number of your database.
I suggest putting the code to create the table in a helper method so that you can call it from both callback methods. This will reduce the chance of an error in case you need to change the code to create the table.
onUpgrade will only be called if you increase the version number.
To implement it you must recreate the tables with any changes you have made and copy over any existing data. There are many tutorials on this topic.
It is not necessary to implement if you are still learning, but if you don't and you make any changes to your schema you'll need to uninstall the app from the device or the changes won't be applied.

ORMLite change allowGeneratedIdInsert in onUpgrade

I'm using ORMLite in my app.
I had to enable the allowGeneratedIdInsert flag for one of my fields (rows) of a class (table). I did this through annotations.
Now i also need to do this for users which will update the app. This means I need to increment the database version and do the same in my onUpgrade method.
Is there an easy way of doing this? Or do I have to copy my data, drop the table and then recreate it using TableUtils?
Unfortunately ORMLite does not help with this field conversion. You certainly can use the raw-update methods to alter your schema in the onUpdate(...) method:
http://ormlite.com/docs/raw-update
For information about upgrading your schema, see the docs:
http://ormlite.com/docs/upgrade-schema

Android concerns with restore database

Imagine the following scenario (I allow backup / restore from my app, I'm doing backup / restore white the entire file.db):
The user make backup of the database.
In the future I do an update on my application which has a new version of the database.
what would happen if the user restore the database with the old version?
How can I avoid this kind of problem?
It would be a good idea to use BackupHelper? I did a simulation of the worst scenario of my database and gave 20k, BackupHelper is recommended for less than 1mb, it would be a good idea to use it? I think my app will never exceed 100kb.
You access SQLite databases via a SQLiteOpenHelper, which provides three callbacks: onCreate(), onUpgrade() and onOpen().
The constructor declares a version parameter, and internally it compares the database version (which is stored in the file) with the supplied argument. If the requested version is newer than the file's, your onUpgrade(db, old, new) is called and you get a chance to alter tables, fill rows and so on.
The restore procedure should simply close all open cursors and helpers and copy the new file in.
May be this is not the best approach but you can do it as:
1- Store the DB Version in the database.
2- After restoring the database, check the DB Version and do the required changes accordingly. Like
void afterRestoration()
{
long dbVersion = get from db;
if(dbVersion == 1)
{
alter table1 add column1;
}
else
{
}
}

Run application/activity at first time

I need to recognize first launch of my application or activity.
At this time I need to get some information from server create local database and save info to it. What is the best way to do this?
Create any preferences for example FirstLaunch and set true \ false to it.
Check whether my database exists or not.
Something else?
PS. All server calls must be into one transaction. Ormlite supports transactions?
Thanks.
For the "create database at first run"-purpose, you should use an SQLiteOpenHelper, which offers you the onCreate()-method that is called when:
[...] the database is created for the first time.
The Database-file itself will be created for you (you don't have to do this manually). In this method, you can then perform actions like populating your database with standard entry's.
If you want to populate the database with informations you get from your server, there might be a problem when there is no Internet-connection available.
In this case, I would check if there is a connection available:
If there is, get your informations.
If not, show a Toast or some other notification to inform the user.
To determine if your Database has be populated with the standard entry's, you can use the database-version which is also provided by the SQLiteDatabase-class:
When you first create your Database-object, you call
SQLiteOpenHelpers constructor and pass it 0 as the Database
version.
If you successfully populated your database, you use
setVersion()-method to alter it to 1.
Later in the onOpen()-method, which is called when the
database is opened, you can check if the database was populated by
using the getVersion()-method.
If it is populated, call the super-method to open it.
If not, try populating it.
Further more, the getReadableDatabase() / getWritableDatabase()-methods should be called off the main-thread anyways because:
Database upgrade may take a long time, you should not call this method
from the application main thread, including from
ContentProvider.onCreate().
So getting the informations from the Internet can take place in the onCreate() and in the onOpen()-method (if it wasn't successful at the first try). You can (for example) use a Service to do this.
If you want to solve this problem with database:
Create database with MyDatabasaVersion table and store your version in a single row, for example db_version default value is 0. First time when the application starts you check the db_version if 0 you need to start the syncronisation, after it is finishing set the db_version to 1.
The easiest way should be sharedpreferences. you can call it everywhere form the application context and you can put boolean values in it.
Here are all Android storages.
you should try first option Create any preferences for example FirstLaunch and set true \ false to it.

Android Architecture: Using multiple ContentProviders and onUpgrade event

My application has two database tables: Products and ShoppingCard. So I created a ProductContentProvider and ShoppingCardContentProvider. Each ContentProvider invokes in its onCreate() method a private class that is child of SQLiteOpenHelper.
From my point of view I would make a global static variable DATABASE_VERSION in a separated ConfigBean that is responsible for both content providers. So if I update that all tables are updated.
=> That does not work. Simply the onUpdate event is never fired.
If you specify a DATABASE_VERSION in each content provider, but with different version numbers in each content provider
=> That does not work. Also it makes no sense, from my point of view, because the paramater in SQLiteOpenHelper is called DATABASE_VERSION not TABLE_VERSION. So in other words, you cannot update any table without updating/throwing an event on all onUpgrade listeners.
If you specify a DATABASE_VERSION in each content provider, but with equal version numbers in each content provider.
=> That works.
Question:
Why can't you make the DATABASE_VERSION a public static variable outside to handle upgrades globaly, or am I completely on the wrong path with my architecture?
The solution to my problem was to create a base class to both content providers. This class holds the only instance of SQLiteOpenHelper. This also ensures that all database tables are created.
I found this information in the post of Ali Serghini, November 5th, 2010.
Okay I have found the reason for the strange behaviour:
I think my approach to make the DATABASE_VERSION an external parameter is right, if you have multiple ContentProviders.
I did just forget that there is yet another ContentProvider: A simple ConfigTable to store the settings. I think I hade a mix of different DATABASE_VERSION values in the end, that leads to re-creating the database on every startup.
After referencing a single param from all ContentProviders, everything worked as expected.
Thanks anyway,
Sebastian

Categories

Resources