im using SQLite OpenHelper to handle database version and it worked fine, my problem is, if i set some updates and new users install my app, the will not get the UPGRADES, because it will run the onCreate using the last DB_VERSION
explaining:
private static final int DB_VERSION = 3;
Context context;
public DB(Context c) {
super(c, DB_NAME, null, DB_VERSION);
context = c;
}
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE table1...");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.d("DBUpgrade", "Atualizando DATABASE");
switch (oldVersion) {
case 2: {
execSQLFromFile(db, "sql2");
}
case 3: {
execSQLFromFile(db, "sql3");
}
}
scenarios:
User 1 has installed since first app release
-> he will get the all the upgrades
User 2 installed for the first time in his device the last release of my apk that has the db_version 3
-> he will not get the upgrades, just the onCreate
ofc i know why this happens but i dont know how to solve it by a simple way, the only i way i throught was to call the onUpgrade(db, 0, DB_VERSION); this enter in the onUpgrade but dont call the cases inside the switch i dont know why, since i send 0, it should call case: 2, because i dont have the break isnt it?
BUT doing this i loose the OnUpgrade for the next version, it will always check the oldVersion, and redo the same code so it will crash because Unique column, alter columns anything
so i still ended without way to onfirst install do the upgrades too =(
User 2 installed for the first time in his device the last release of my apk that has the db_version 3 -> he will not get the upgrades, just the onCreate
There are no "upgrades", as there is no database to upgrade. onCreate() must be implemented to create a database with the proper (latest) schema.
Related
I'm trying to implement version control into my database. I have following code:
if (File.Exists (dbPath)) {
database = new SQLiteConnection(dbPath);
dbVersion = GetDatabaseVersion();
if (dbVersion != DATABASE_VERSION) {
CreateDatabase(dbPath);
database = new SQLiteConnection(dbPath);
SetDatabaseVersion(DATABASE_VERSION);
}
} else {
CreateDatabase(dbPath);
database = new SQLiteConnection(dbPath);
SetDatabaseVersion(DATABASE_VERSION);
}
When I run the code for the first time File.Exists (dbPath) returns false as expected. When I then stop the app and build and deploy again, File.Exists (dbPath) returns true (as expected) and the versions get checked. But when I change an entry in the database (not the version) and I build and deploy again File.Exists (dbPath) returns false. So I guess the sqlite-file gets deleted when it's changed?
What I want to achieve is that when the sqlite-file is changed, but the version numbers are still the same, the database of the app isn't updated. Only when the versions don't match, it has to be updated.
(It works perfectly for iOS this way, by the way)
Can anyone help me?
Thanks in advance.
It's difficult, without access to your debugger, to answer what's going wrong. However, your way of creating and updating your database looks unusual and unnecessarily complicated. You should consider using SQLiteOpenHelper, which will allow you a structure like this:
public class MyDatabase extends SQLiteOpenHelper {
private static final int VERION = ...;
public MyDatabase(Context context) {
super(context, "mydatabasename", null, VERION);
}
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table...");
...
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, intNewVersion) {
db.execSQL("...") // whatever you have to change from one version to another
}
}
This works without losing any database files.
You should tick this box in Visual Studio / Tools / Options / Xamarin / Android settings
I have an app that is being used by beta testers. My original schema did not end up working for my actual implementation of the feature I'm currently working on. I want to update the database. I do not want my testers to lose their data.
My understanding is that the steps for this are:
1) Leave my SQLiteOpenHelper class's onCreate method AS IS. I leave it as it is currently / originally written, the "version one" schema as I think of it.
UPDATE 2015-04-19: Step One is WRONG. See my own (accepted) answer below for details.
2) Fill in my SQLiteOpenHelper class's onUpgrade method. Here I make all the changes to go from the first schema to the second. (and in the future maybe write the changes needed to go from the second schema to a third)
3) Update the database version. In my app, I keep this as a static var. When I'm ready to pull the trigger and update the database, I change this var (DB_VERSION) from 1 to 2. This var being 2 versus the app installed on the device having a version of 1 is what triggers onUpgrade() to be called the first time the database is opened (in my case, the app's onCreate).
public static final int DB_VERSION = 1;
...
class DBHelper extends SQLiteOpenHelper {
public DBHelper() {
super(context, DB_NAME, null, DB_VERSION);
}
4) Run my app and cross my fingers. If I get an error / made a typo in my SQL, I uninstall and run again.
Can anyone verify if that is correct? Or if I'm overlooking something?
The tutorials I've found -- when they don't just drop and recreate the database, changing the onCreate to the new schema -- don't really discuss when you already have an app and need to make a change. I guess it's not relevant to a beginner, and assumed knowledge for a non-beginner? For upgrades with user data that can't be thrown away, I only have been able to find specific question/answers about a single aspect of the upgrade, not a comprehensive guide. I'm afraid I could be missing something that's so basic/important that it "goes without saying", hence my apprehension/fear to just do it. I've searched as best as I am able, could really use some guidance! Thanks in advance for any help!
That is correct. You are increasing version and updating db.
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if(oldVersion < 2) {
db.execSQL("blablabla");
}
if(oldVersion < 3) {
db.execSQL("new blablabla");
}
if(oldVersion < 4) {
db.execSQL("newest blablabla");
}
}
> Can anyone verify if that is correct?
Yes
Thats the way it worked for my android apps. My code looks like this:
public class DatabaseHelper extends SQLiteOpenHelper {
public static final int DATABASE_VERSION_3_MYTABLE_WITH_NOTES = 3;
public static final int DATABASE_VERSION_4_CATEGORY_ACTIVE = 4;
public static final int DATABASE_VERSION_5_REPORT_VIEW = 5;
// points to latest version
public static final int DATABASE_VERSION = DatabaseHelper.DATABASE_VERSION_5_REPORT_VIEW;
public DatabaseHelper(final Context context, final String databaseName) {
super(context, databaseName, null, DatabaseHelper.DATABASE_VERSION);
....
}
#Override
public void onUpgrade(final SQLiteDatabase db, final int oldVersion,
final int newVersion) {
Log.w(this.getClass().toString(), "Upgrading database from version "
+ oldVersion + " to " + newVersion + ". (Old data is kept.)");
if (oldVersion < DatabaseHelper.DATABASE_VERSION_3_MYTABLE_WITH_NOTES) {
this.version3Upgrade_MYTABLE_WITH_NOTES(db);
}
if (oldVersion < DatabaseHelper.DATABASE_VERSION_4_CATEGORY_ACTIVE) {
this.version4Upgrade_CATEGORY_ACTIVE(db);
}
if (oldVersion < DatabaseHelper.DATABASE_VERSION_5_REPORT_VIEW) {
this.version5Upgrade_REPORT_VIEW(db);
}
}
private void version3Upgrade_MYTABLE_WITH_NOTES(final SQLiteDatabase db) {
// added MYTABLE.notes
db.execSQL("ALTER TABLE " + MyTable.TABLE
+ " ADD COLUMN " + MyTable.COL_NOTES + " TEXT");
}
I have one const and one method to upgrade from one version to the next.
Sorry self-from-3-months-ago, turns out that's WRONG!
The problem is in step one. The onCreate is NOT left as is. It needs to create the newest version of the database. onUpdate is only called when an EXISTING user updates to the newest app release. Anyone doing a CLEAN INSTALL would end up with the old scheme, never calling onUpdate.
Here is the skeleton of my new code, which seems to handle both clean installs and upgrades. (At least I hope it does.)
class DBHelper extends SQLiteOpenHelper {
public DBHelper() {
super(context, DB_NAME, null, DB_VERSION);
Log.i(TAG, "DBHelper called with DB_NAME " + DB_NAME + " and DB_VERSION " + Integer.toString(DB_VERSION));
}
#Override
public void onCreate(SQLiteDatabase db) {
setupV1(db);
upgradeV2(db);
}
#Override
public void onUpgrade(
final SQLiteDatabase db, final int oldVersion,
final int newVersion)
{
int upgradeTo = oldVersion + 1;
Log.i(TAG, "Upgrading database to version " + Integer.toString(upgradeTo));
while (upgradeTo <= newVersion)
{
switch (upgradeTo)
{
// Database v2. Added X Functionality
case 2:
upgradeV2(db);
break;
// Database v3 (not created yet)
// case 3:
// // something here
// break;
}
upgradeTo++;
}
}
private void setupV1(final SQLiteDatabase db) {
// CODE HERE TO CREATE VERSION / SCHEMA ONE OF MY DATABASE
}
private void upgradeV2(final SQLiteDatabase db) {
// CODE HERE TO UPDATE FROM VERSION ONE TO VERSION TWO
}
}
I am developing a database application and I am stuck up at one place.
The scenario is: I have a database and I am maintaining the version of the database.
It is the same as that of the application version.
Now I am implementing the database in version 1. There are 3 tables getting created in version 1. In version 2, I am upgrading the database by adding one more table. Hence, the query is in the upgrade().
Now, what if the user installs version 2. The onUpgrade() will not get called because there is no database. Hence, the onCreate() will be called and the consequence will be it will create only 3 tables.
I was thinking to call the onUpgrade() explicitly in the onCreate(). But many developers on stackoverflow have suggested not to call it explicitly.
I am completely stranded.
Thanks in advance.
I know it's an old post, you have certainly found a solution, but I find the question valid (upvoted) and as it did not receive an answer, here are my 2 cents:
Calling onUpgrade() from onCreate() should work (I did not test it), but there is a better way to organize you helper (see snippet hereafter). The key point is that both those methods are just entry points.
public class SampleDBHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "mydatabase";
private static final int DB_VERSION = 2;
public SampleDBHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
updateDatabase(db, 0, DB_VERSION);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
updateDatabase(db, oldVersion, newVersion);
}
private void updateDatabase(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < 1) {
// Create 3 initial tables
}
if (oldVersion < 2) {
// Create the new table
}
}
}
The advantages of this kind of helper:
You never need to change onCreate() and onUpgrade() methods, only updateDatabase().
For each new version, you just need to :
increment DB_VERSION
add a new section if (oldVersion < N) { // do the upgrade }.
Credit : Strongly inspired from Head First Android Development, Dawn and David Griffiths, O'Reilly, 2015
I have an app released on the android market which uses sqlite and displays data. I want to know if I am sending an update for the app by adding features, should I upload a new database? What happens when users already having my app, click on update? Will the database update on its own? If the users are downloading my app for the first time, they will certainly get the new db content...but what about the existing users?? I want to know if I have to explicitly update the database in the program
When you create your new version... If you change the version of the database... The onUpgrade function will run on all the existing users:
public static final int dbVersion = 2;
protected static class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context) {
super(context, dbName, null, dbVersion);
}
#Override
public void onCreate(SQLiteDatabase db) {
//create tables
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//what do you want to do to existing users? maybe recreate?
}
}
Why not create the sqlite database through code? That way your updates can update the SQL on the database (alter columns, add rows) without affecting the users existing data.
If you are changing database's attributes then on updation it will create problem and if the database's attributes are same then it will not have any effect...
You may use android.database.sqlite.SQLiteOpenHelper class it supports versions and migration mechanism
Typically, for a WinForm or a Web App, I create the database and tables through the RDBMS or through a separate install process. However, I haven't seen anything of the sort in Android. All the examples I've seen have the database creation scripts embedded in an activity like this.
The best thing I can come up with now is to call a method from the data access constructor to check whether the database is installed - if not - install it. However, this seems like a lot of overhead to me.
What's the cleanest way to execute a android database install and then forget about it?
When using SQLLiteOpenHelper (http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html), the onCreate method will be called only if the database doesn't exist. onUpgrade will be called when a new version of the database is introduced.
IF the database already exists, and no version upgrade occured, these methods won't be executed.
There is no need for implementing if-else checks in your activity.
private static class DatabaseHelper extends SQLiteOpenHelper
{
DatabaseHelper(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db)
{
db.execSQL(DATABASE_CREATE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion,
int newVersion)
{
Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion);
db.execSQL(DATABASE_UPGRADE);
}
}