I'm using GreenDao 3.2.2 for my DB,
On my first run on creating Entities via #tags everything worked ok.
Now I am editing the gradle schema to higher versions because I added some props to a table:
greendao {
schemaVersion 4
}
However the OpenHelper onUpgrade method is never called, thus my project is always crashing because some columns are not found.
Application class
//Init DB
UpgradeHelper helper = new UpgradeHelper(this, ENCRYPTED ? "db-encrypted" : "db", null);
Database db = ENCRYPTED ? helper.getEncryptedWritableDb("app-cipher") : helper.getWritableDb();
daoSession = new DaoMaster(db).newSession();
OpenHelper class
public class UpgradeHelper extends DaoMaster.OpenHelper {
public UpgradeHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//never gets called
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion);
//do migrations
}
}
am I missing something?
Got it!!! After hours of searching and reading GreenDAO code I understood the problem.
The problem is that getEncryptedWritableDb creates another kind of DB that does not extends SQLiteDatabase. So even when the EncryptedHelper gets the onUpgrade method, my helper class didn't catch it because it fell into another signature.
The solution was simply using the other signature that receives a DAO Database interface:
public void onUpgrade(Database db, int oldVersion, int newVersion) {
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by migrating all tables data");
//do migration
}
of course I needed to update all my Migration methods to receive a Database object instead of a StandardDatabase
this is my Generator class
public class Generator {
public static void main(String[] args) throws Exception {
Schema schema = new Schema(1, "app.abc.db.dao");
createAbcDB(schema);
}
private static void createAbcDB(Schema schema) throws IOException, Exception {
Entity abc = schema.addEntity("Abc");
abc.addIdProperty();
abc.addShortProperty("name");
}
}
This is the code where i get abc dao from dao session. This works fine.
DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(SurveyActivity.this, "abc.db", null);
SQLiteDatabase db = devOpenHelper.getWritableDatabase();
DaoMaster daoMaster = new DaoMaster(db);
DaoSession daoSession = daoMaster.newSession(IdentityScopeType.None);
abcDao = daoSession.getAbcDao();
I added one more column
abc.addShortProperty("email");
to createAbcDB in generator to new version of app. Once users get updated they are getting sql exception saying no column found. Because i am calling on new login
dropAllTables(db, true);
onCreate(db);
But problem is i have given one time login that user will always come to landing screen on upgrade from play store. So i don't know whether the user is upgraded app or not in order to drop and create all tables.
So my question is how to know my table has altered?
Each time that you do a significant modification like this, you have to update de Schema version number:
Schema schema = new Schema(2, "app.abc.db.dao");
This way, in the OpenHelper present in the DaoMaster, or in the SQLiteOpenHelper taht you're using, you can control this changes in onUpgrade() function:
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
dropAllTables(db, true);
onCreate(db);
}
I have the following problem:
I have a App in the Store, version code 1 now I'm working on a update for this app.
The problem is, that if the user already saved data, I must update the data when the user run the app the first time after updating to version code 2.
my question is, how to implement this in android? Is this possible?
the pseudo code should look like this:
protected void onCreate(Bundle savedInstanceState) {
if (old_version == 1 && version_now == 2)
{
// my update code which will only performed once in a lifetime of the app
}
// ...
}
Read the app version, run your code and store in the SharedPreferences, that you already run your code. Very nice described in these questions:
App version/name: How to get the build/version number of your Android application?
Run only once: Run code only once after an application is installed on Android device
If you are using SQLiteOpenHelper to manage your queries, there is a method called OnUpgrade that will get called when a user has upgraded his app, and the new version of the app has a version code larger than the previous.
An example use:
public static void onUpgrade(SQLiteDatabase database, int oldVersion,
int newVersion) {
Log.w(TodoTable.class.getName(), "Upgrading database from version "
+ oldVersion + " to " + newVersion
+ ", which will destroy all old data");
database.execSQL("DROP TABLE IF EXISTS " + TABLE_TODO);
onCreate(database);
}
Here you can use oldVersion and newVersion to do incremental updates of your database if you don't want to just drop your tables. You have to make sure that you increment the database version number. The database version number is passed as a constructor argument to SQLiteOpenHelper.
An example of incremental upgrades:
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (newVersion > oldVersion) {
db.beginTransaction();
boolean success = true;
for (int i = oldVersion ; i < newVersion ; ++i) {
int nextVersion = i + 1;
switch (nextVersion) {
case 2:
success = upgradeToVersion2(db);
break;
// etc. for later versions.
case 3:
success = upgradeToVersion3(db);
break;
}
if (!success) {
break;
}
}
if (success) {
db.setTransactionSuccessful();
}
db.endTransaction();
}
}
I have one problem with Android SQLite database.
I have one table which contains one field.StudentFname
and that application is working fine with Android 2.3.1 and now if I add another field then my application is not working properly.
Can anyone help me who knows database very well,
you can use ALTER TABLE function on your onUpgrade() method, like this:
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// If you need to add a column
if (newVersion > oldVersion) {
db.execSQL("ALTER TABLE foo ADD COLUMN new_column INTEGER DEFAULT 0");
}
}
Obviously, the SQLite will differ depending on the column definition.
I came across this thread when needing help on my own app, but saw issues with many of the answers. I would recommend doing the following:
private static final String DATABASE_ALTER_TEAM_1 = "ALTER TABLE "
+ TABLE_TEAM + " ADD COLUMN " + COLUMN_COACH + " string;";
private static final String DATABASE_ALTER_TEAM_2 = "ALTER TABLE "
+ TABLE_TEAM + " ADD COLUMN " + COLUMN_STADIUM + " string;";
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < 2) {
db.execSQL(DATABASE_ALTER_TEAM_1);
}
if (oldVersion < 3) {
db.execSQL(DATABASE_ALTER_TEAM_2);
}
}
You want to make sure the code will work when users upgrade more than 1 version and that the update statement only runs the one upgrade it is needed. For a bit more on this, check out this blog.
The easiest way to do this is to add some SQL to the onUpgrade() method in your SQLiteOpenHelper class. Something like:
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// If you need to add a new column
if (newVersion > oldVersion) {
db.execSQL("ALTER TABLE student ADD COLUMN student_rollno INTEGER DEFAULT 0");
}
}
Perhaps a slightly more elegant approach using switch instead of if/then that will upgrade from any schema to the most recent schema...
Here's also a decent page on the syntax for altering a table: http://alvinalexander.com/android/sqlite-alter-table-syntax-examples
public static final String TABLE_TEAM = "team";
public static final String COLUMN_COACH = "coach";
public static final String COLUMN_STADIUM = "stadium";
private static final String DATABASE_ALTER_TEAM_TO_V2 = "ALTER TABLE "
+ TABLE_TEAM + " ADD COLUMN " + COLUMN_COACH + " TEXT;";
private static final String DATABASE_ALTER_TEAM_TO_V3 = "ALTER TABLE "
+ TABLE_TEAM + " ADD COLUMN " + COLUMN_STADIUM + " TEXT;";
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion)
{
case 1:
//upgrade from version 1 to 2
db.execSQL(DATABASE_ALTER_TEAM_TO_V2);
case 2:
//upgrade from version 2 to 3
db.execSQL(DATABASE_ALTER_TEAM_TO_V3);
//and so on.. do not add breaks so that switch will
//start at oldVersion, and run straight through to the latest
}
}
I have done the following approach, it is resovled for me
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
#Aamirkhan.i think you would have solved the problem you mentioned in the comments long back ago.i think you didn't increase the data base version. or else the answers here are straight forward.i am writing this because it might help anyone who hasn't increased or changed their data base version number when they are altering a table.
I think we should not check condition like that
if (newVersion > oldVersion) {
}
because if we use this , it means every time when we increase the database version then onUpdrade() will call and condition will be true , so we should check like that
if(oldVersion==1)
{
}
so in this case if old version is 2 then condition will be false and user with old version 2 will not update the database(which user wants only for version 1), because for those users database had already updated .
To add a new column to the table you need to use ALTER. In android you can add the new column inside the onUpgrade().
You may be wonder, how onUpgrade() will add the new column?
When you implementing a subclass of SQLiteOpenHelper, you need to call superclass constructor: super(context, DB_NAME, null, 1); in your class constructor. There I have passed 1 for version.
When I changed the version 1 to above(2 or greater), onUpgrade() will invoked. And perform the SQL modifications which I intend to do.
My class constructor after changed the version:
public DatabaseHelper(Context context) {
super(context, DB_NAME, null, 2);//version changed from 1 to 2
}
SQL modifications checks like this, superclass constructor compares the version of the stored SQLite db file with the version that I passed to super(). If these(previous and now) version numbers are different onUpgrade() gets invoked.
Code should look like this:
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// add new columns to migrate to version 2
if (oldVersion < 2) {
db.execSQL("ALTER TABLE " + TABLE_NAME + "ADD COLUMN school VARCHAR(250)");
}
// add new columns to migrate to version 3
if (oldVersion < 3) {
db.execSQL("ALTER TABLE " + TABLE_NAME + "ADD COLUMN age INTEGER");
}
}
Simply change in your code
private final int DATABASE_VERSION = 1;
to
private static final int DATABASE_VERSION =2;
first, increment the database version number. and then in onUpgrade method, you can check if the column exists already if not then only add the column
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if(!existsColumnInTable(db, TABLE_NAME, COLUMN_NAME)){
db.execSQL("ALTER TABLE foo ADD COLUMN COLUMN_NAME INTEGER DEFAULT 0");
}
}
private boolean existsColumnInTable(SQLiteDatabase inDatabase, String inTable, String columnToCheck) {
Cursor cursor = null;
try {
// Query 1 row
cursor = inDatabase.rawQuery("SELECT * FROM " + inTable + " LIMIT 0", null);
// getColumnIndex() gives us the index (0 to ...) of the column - otherwise we get a -1
if (cursor.getColumnIndex(columnToCheck) != -1)
return true;
else
return false;
} catch (Exception Exp) {
return false;
} finally {
if (cursor != null) cursor.close();
}
}
this method is extracted from this link Checking if a column exists in an application database in Android
I came across link while searching for the same issue. It explains how to use upgrade.
https://thebhwgroup.com/blog/how-android-sqlite-onupgrade
it explains why to use this below code
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < 2) {
db.execSQL(DATABASE_ALTER_TEAM_1);
}
if (oldVersion < 3) {
db.execSQL(DATABASE_ALTER_TEAM_2);
}
}
The easiest way to create a new column on a table is add some SQL to the onUpgrade() method in SQLiteOpenHelper class. Like:
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion) {
case 1:
db.execSQL(SQL_MY_TABLE);
case 2:
db.execSQL("ALTER TABLE myTable ADD COLUMN myNewColumn TEXT");
}
}
Noticed no answers look for the existence of a column:
Cursor cursor = database.rawQuery("SELECT * FROM " + MY_TABLE, null);
int columnIndex = cursor.getColumnIndex(MY_NEW_COLUMN);
if (columnIndex < 0) {
database.execSQL("ALTER TABLE " + MY_TABLE + " ADD COLUMN " + MY_NEW_COLUMN + " TEXT");
}
So, I'm working with an Android SQLite database, with SQLiteOpenHelper. It seems to have a concept of database versions and upgrading... but it looks like you're supposed to roll your own code to actually do the upgrades, and keep your onCreate method up-to-date with your updates.
Coming from a Rails development background, this seems a little primitive. For the uninitiated, Rails allows you to just write a class-per-version-upgrade, and Rails takes care of applying whichever versions need to be... this applies for DB creation, too; you only have one representation of your database schema, the set of migrations. Rails also does a DB-independent representation of the schema changes, but that isn't necessary for Android because it only supports SQLite (which is fine).
Has anyone written a decent schema migration helper class for Android that allows me to get closer to DB schema management nirvana (RailsEdition(TM))? It'll save me rolling my own ugly implementation.
Given that I didn't find anything that supported Android, actually worked, didn't require me to subscribe to an insane database world view, and didn't cost a lot (hobby project, no dice), I came up with the following bodgy hack. It's not clever, but it at least allows me to think about my schemas in a way that I'm familiar with. I don't expect it'd work real well for a large codebase/database schema, but if you've got that you can probably afford to pay for something.
public class AppDatabase extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "main";
public static final int LATEST_VERSION = 4;
public static SQLiteDatabase open(Context ctx) {
AppDatabase db = new AppDatabase(ctx);
return db.getWritableDatabase();
}
public AppDatabase(Context ctx) {
super(ctx, DATABASE_NAME, null, LATEST_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
onUpgrade(db, 0, LATEST_VERSION);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
for (int i = oldVersion+1; i <= newVersion; i++) {
switch (i) {
case 1:
db.execSQL("CREATE TABLE blah ( " +
"id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," +
"start CHAR(4)," +
"end CHAR(4)" +
")");
break;
case 2:
db.execSQL("CREATE TABLE fortnights ( " +
"first_day DATE PRIMARY KEY" +
")");
break;
case 3:
db.execSQL("ALTER TABLE shifts ADD top CHAR(4)");
db.execSQL("ALTER TABLE shifts ADD bottom CHAR(4)");
db.execSQL("UPDATE shifts set top=start, bottom=end");
break;
case 4:
db.execSQL("ALTER TABLE shifts ADD callout BOOLEAN DEFAULT 0");
break;
}
}
}
}