I have an SQLite database that I created in Android that I'm manually managing all the code for to perform my reading and writing. I recently discovered ORMlite. I want to use ORMlite to manage my database from this point forward. The issue is the application is already on the android market and I don't want my user's to lose their data.
Is there a way I can tell ORMlite to start managing the already made database? Or is there a standard practice to read all of my data from the old database and write it to a new one?
Well after doing a fair amount of due diligence I realized how simple of a task this is. Ormlite actually sits on top of the built-in SQLite. No code is needed to move to Ormlite. I simple reference my database name within my Ormlite Helper Class.
My code is below. I hope this helps someone else in the future.
public class OrmHelper extends OrmLiteSqliteOpenHelper {
private final String TAG = this.getClass().getSimpleName();
private Context context;
public OrmHelper(Context context) {
//references my Sqlite dbnames. I made them static in the SqlHelper class
super(context, DataBase.DB_Name, null, DataBase.DB_Version);
this.context = context;
}
#Override
public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) {
try {
Log.i(TAG, "Creating database in Ormlite");
TableUtils.createTable(connectionSource, Model.class);
TableUtils.createTable(connectionSource, UserCredential.class);
} catch (SQLException e) {
Log.e(TAG, "Error creating database", e);
}
}
#Override
public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource,
int oldVersion, int newVersion) {
}
/**
* this genric method is for grabbing the Dao for any ormlite table
*/
public <T, V> Dao<T, V> getTypeDao(Class<T> classType, Class<V> idType)
throws SQLException{
return getDao(classType);
}
}
Related
I've added a column(description) to my table account. I also read this guild to upgrade my database. However, I had a bit confusing of what is getHelper() method in this code:
Dao<Account, Integer> dao = getHelper().getAccountDao();
// change the table to add a new column named "description"
dao.executeRaw("ALTER TABLE `account` ADD COLUMN description INTEGER;");
and where did it come from? I didn't see getHelper() was declared in my DatabaseHelper class. Can someone help me?
You should have a class extending OrmLiteSqliteOpenHelper where you create the tables (in onCreate) and update them (in onUpgrade):
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public DatabaseHelper(Context context) {
super(context, "database.db", null, 1);
}
#Override
public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) {
try {
TableUtils.createTable(connectionSource, Account.class);
} catch (SQLException e) {
throw new RuntimeException("Error when create database tables", e);
}
}
#Override
public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
database.execSQL("ALTER TABLE `account` ADD COLUMN description INTEGER;");
//same as:
//AccountDAO dao = getDao(Acount.class);
//dao.executeRaw("ALTER TABLE 'account' ADD COLUMN description INTEGER;");
}
}
OrmLiteBaseListActivity, OrmLiteBaseService and
OrmLiteBaseTabActivity provide a method getHelper to access the
database helper whenever it is needed and will automatically create
the helper in the onCreate() method and release it in the onDestroy()
method.
Furthermore, if you are using classes above, you should have something like this:
public class MyACtivity extends OrmLiteBaseActivity<DatabaseHelper> {
//In this class, you can call getHelper() to obtain the DatabaseHelper instance
}
My app used ormlite to communicate with Sqlite database. There are many screens that get data from ormlite. The problem is I want to update the database in background without user' knowledge (it's transparent to user) and my app use some CursorAdapters and Loaders to get data. The behavior look like this: my app check if there is new version in server, it will download new db file from server, then change current db file from local by new server db file in ormlite helper. While update progress is happening, user can change screen or view data from db normally (I just use the select query)
I have searched some answer, they advised use onUpgrade method, but how can I apply this in my case, because I want to change completely the database file? And how can I switch the database while selecting data?
Here is my db helper:
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public DatabaseHelper(Context context){
super(context, "document.sqlite", null, 1);
}
#Override
public void onCreate(SQLiteDatabase db, ConnectionSource connectionSource) {
try {
TableUtils.createTable(connectionSource, Category.class);
TableUtils.createTable(connectionSource, Book.class);
} catch (Exception ex) {
Ln.e(ex);
}
}
#Override
public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int oldVersion,
int newVersion) {
try{
TableUtils.dropTable(connectionSource, Category.class, true);
TableUtils.dropTable(connectionSource, Book.class, true);
// get new one
onCreate(db, connectionSource);
}catch(Exception ex){
Ln.e(ex);
}
}
Any help would be appreciated!
I had similar situation in my project in which I had to refresh database with new data after checking for new data.After trying so many methods Finally I reached at one solution.I do not know if that solution is optimal one but after testing it is working fine.
Solution is as follows:-
I am getting new data in json form so I am creating a new blank database with temp_original-database-name.db and then populating it with new data(in your case you have complete database downloading from server , so you do not need extra helper for creating temporary database). After this data is populated then I am renaming this database temp_original-database-name.db to original-database-name.db using file system methods.
I have done testing and original helper instance used for original database still exists even after still second rename of database operation.and everything works fine.
Hope this can help.Please tell me if this helps and if you have any other question regarding this.
I have seen another question about schema upgrade/migration using green dao (here)
There are lots of links in that answer for a good pattern to use when doing schema upgrades - however there are no examples of what you actually do to your data to migrate it properly and I'm having trouble finding anything.
In my case, my migration is incredibly straight forward - I do not wish to transform any existing data, I simply need to add some new tables to my schema, which I suspect is a fairly common situation.
What is the easiest way to add new tables to your schema without deleting data your users have already saved? A specific example would be greatly appreciated.
It would be awesome if greenDao provided a class similar to DevOpenHelper that would simply add new tables/columns that didn't previously exist in the schema without dropping existing tabes/data first.
I finally had time to dig in to this myself and realized it's quite easy to add a new table while retaining data in old tables.
DISCLAIMER: While I realize this implementation is specific to my scenario, I think it's helpful for someone like me who has used an Android ORM tool (greenDao) exclusively to deal with SQLite on Android. I understand this is pretty common for those of you who have written your own table creation queries from the beginning, but for someone who has been sheltered from the guts of using a SQLite DB with Android, I think this example will be helpful.
ANSWER:
You can either modify the DevOpenHelper inner class or create your own class. I chose to edit DevOpenHelper for the time being to keep my example simple - however, note that if you regenerate your greendao classes, DevOpenHelper will be overwritten. It would be a better idea to create your own class like "MyOpenHelper" and use that instead.
Before my changes, DevOpenHelper.onUpgrade looked like this:
#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);
}
Instead of dropping all tables, take a look at the createAllTables method that is auto-generated by GreenDao.
Rewrite onUpgrade to check if the "oldVersion" is the one you want to upgrade from, then only call the createTable methods for "new" tables. Here is what my onUpgrade method looks like now:
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " +
//Going from older schema to new schema
if(oldVersion == 3 && newVersion == 4)
{
boolean ifNotExists = false;
//Leave old tables alone and only create ones that didn't exist
//in the previous schema
NewTable1Dao.createTable(db, ifNotExists);
NewTable2Dao.createTable(db, ifNotExists);
NewTable3Dao.createTable(db, ifNotExists);
NewTable4Dao.createTable(db, ifNotExists);
}
else
{
dropAllTables(db, true);
onCreate(db);
}
}
Adding a new column would be similar, except you'd have to write some SQL or take a look at the auto-generated SQL create statements from greenDao and leverage those.
To add a single new column (NEW_COLUMN, assuming it's an INTEGER type) to an existing table (EXISTING_TABLE), do the following:
db.execSQL("ALTER TABLE 'EXISTING_TABLE' ADD 'NEW_COLUMN' INTEGER");
For me right now, all I needed to do was add new Tables so this ended up being rather straight forward. Hopefully someone else finds this useful.
I made an slightly different approach to handle the updates automatically no matter where the previous user comes from.
First I created a Class that implements the method onUpgrade on a SQLDatabase
public abstract class AbstractMigratorHelper {
public abstract void onUpgrade(SQLiteDatabase db);
}
From this class will inherit all the migrators helpers I will declare afterwards
I will write an example of one of them
public class DBMigrationHelper5 extends AbstractMigratorHelper {
/* Upgrade from DB schema x to schema x+1 */
public void onUpgrade(SQLiteDatabase db) {
//Example sql statement
db.execSQL("ALTER TABLE user ADD COLUMN USERNAME TEXT");
}
}
After this you need to implement the logic on the class that is actually called on upgrade, where you will need to remove the previous DevOpenHelper for a custom one that could look like this
public static class UpgradeHelper extends OpenHelper {
public UpgradeHelper(Context context, String name, CursorFactory factory) {
super(context, name, factory);
}
/**
* Here is where the calls to upgrade are executed
*/
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
/* i represent the version where the user is now and the class named with this number implies that is upgrading from i to i++ schema */
for (int i = oldVersion; i < newVersion; i++) {
try {
/* New instance of the class that migrates from i version to i++ version named DBMigratorHelper{version that the db has on this moment} */
AbstractMigratorHelper migratorHelper = (AbstractMigratorHelper) Class.forName("com.nameofyourpackage.persistence.MigrationHelpers.DBMigrationHelper" + i).newInstance();
if (migratorHelper != null) {
/* Upgrade de db */
migratorHelper.onUpgrade(db);
}
} catch (ClassNotFoundException | ClassCastException | IllegalAccessException | InstantiationException e) {
Log.e(TAG, "Could not migrate from schema from schema: " + i + " to " + i++);
/* If something fail prevent the DB to be updated to future version if the previous version has not been upgraded successfully */
break;
}
}
}
}
So if you are careful naming your Migration Helpers (i.e. MigrationHelper5 does the migration from schema 5 to schema 6) you can implement this logic and then in every MigratorHelper class just implement the execSQL call with all the sql code that you need to implement.
Finally one more remark, if you are working with proguard, the method find name by class might not work, since class names are changed when obfuscating the code. You might want to consider add an exception on the proguard configuration file (proguard-rules.pro) to exclude any class that extend from AbstractMigratorHelper
# Avoid errors when upgrading database migrators
-keep public class * extends yourpackage.locationofyourclass.AbstractMigratorHelper
I do it a slightly different way.
I add my new #DatabaseTable classes and any #DatabaseFields to existing #DatabaseTable classes and run DatabaseConfigUtil.
Then I'll add a new method to my DatabaseUpgrader class and modify my DatabaseHelper, changing the DATABASE_VERSION value and the onUpdate method
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static final int DATABASE_VERSION = 3;
#Override
public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int oldVersion, int newVersion) {
if (newVersion > oldVersion) {
switch (oldVersion) {
case 1:
DatabaseUpdater.from1to2(connectionSource);
DatabaseUpdater.from2to3(connectionSource);
break;
case 2:
DatabaseUpdater.from2to3(connectionSource);
break;
default:
onCreate(db);
}
}
}
public static DatabaseHelper getInstance() {
return DatabaseHelper.mHelper;
}
public static void setInstance(Context context) {
DatabaseHelper.mHelper = new DatabaseHelper(context);
}
…
}
And then in the DatabaseUpdater class
public class DatabaseUpdater {
private static final String TAG = "DatabaseHelper";
public static void from1to2(ConnectionSource connectionSource) {
try {
DatabaseHelper helper = DatabaseHelper.getInstance();
//Example add a table
TableUtils.createTable(connectionSource, AnotherEntity.class);
} catch (SQLException e) {
Log.e(TAG, "Error upgrading database to v2: ", e);
} catch (java.sql.SQLException e) {
e.printStackTrace();
}
}
public static void from2to3(ConnectionSource connectionSource) {
try {
DatabaseHelper helper = DatabaseHelper.getInstance();
//Example add a field to a table
RuntimeExceptionDao<MyEntity, Integer> myDao = helper.getMyDao();
diaryDao.executeRaw("ALTER TABLE myEntity ADD firstNewField");
diaryDao.executeRaw("ALTER TABLE myEntity ADD anotherNewField");
} catch (SQLException e) {
Log.e(TAG, "Error upgrading database to v3: ", e);
}
}
}
To answer question posted by #MBH on first answer. Also I did not find the answer in this post hence adding.
GreenDAO uses the schema version number from build.gradle file. Gradle file should contain below
android {
...
}
greendao {
schemaVersion 1
}
Refer this link for more information. Then on upgrade change this number to 2 or any increment. Based on that number GreenDAO calls below API from android.database.sqlite.SQLiteDatabase.DatabaseOpenHelper.java
public DatabaseOpenHelper(Context context, String name, int version)
As standard approach by Sqlite DB upgrade, it calls below API
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
As other answers suggest, this method can be overridden in derived class and can handle any project specific upgrades.
Hope this helps.
Here is my model classes that are persisted in sqlite db using ORMLITE.
public class Site{
...
...
Collection<Visit> visits;
}
public class Visit{
...
...
Collection<Pic> pics;
}
public class Pic{
...
...
}
Now in one view i add,edit or delete from these three tables. There is a button in my view to cancel the changes(add,edit,delete). So i need to rollback to previous state of the db.
How can i achieve this roll back to a certain state of the three tables using ormlite with android?
I have read in ormlite docs about DAO.SetAutoCommit() and startThreadConnection() methods. I think i can do it by using this two. But cant figure it out how to use them. Please suggest me how to do it.
Here is my DBHelper Class:
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
// name of the database file
private static final String DATABASE_NAME = "Test.db";
private static final int DATABASE_VERSION = 1;
private Dao<Site, Integer> siteListDao = null;
private Dao<Visit, Integer> visitDao= null;
private Dao<Pic,Integer> picDao=null;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase database,ConnectionSource connectionSource) {
try {
TableUtils.createTable(connectionSource, Site.class);
TableUtils.createTable(connectionSource, Visit.class);
TableUtils.createTable(connectionSource, Pic.class);
} catch (SQLException e) {
Log.e(DatabaseHelper.class.getName(), "Can't create database", e);
throw new RuntimeException(e);
} catch (java.sql.SQLException e) {
e.printStackTrace();
}
}
public Dao<Visit, Integer> getVisitDao() {
if (null == visitDao) {
try {
visitDao = getDao(Visit.class);
}catch (java.sql.SQLException e) {
e.printStackTrace();
}
}
return visitDao;
}
.....
.....
Hmm don't know about any methods that will do this for you automatically. If you really wanna do it automatically, you could also check out Transactions. They have build-in controls to roll-back on fail. Not exactly what you want, but maybe adjustable.
You could also just do it more manually and save 1 (last) object in memory, the object you're going to delete. If a person wants to 'undo' the change, you can just re-add that object with ORMLite. Probably a lot easier than other options.
Yeah I mostly agree with #Stefan. I think you need to do this inside of your application and not rely on a database construct to all you to return to a previous state.
Turning off auto-commit (which ORMLite uses transactions under Sqlite) or using transactions directly is not how to do this. Transactions are designed to allow you to make multiple changes to the database and then roll them all back if one database change fails. They are not intended to stay open for seconds waiting for user input.
You could have a committed boolean field or some such in your data to make it easier to "revert" the database by deleting all objects where the committed = false or some such.
You could have separate tables so objects are stored to a session table and then copied over to the main tables when the user commits their work.
I have a small problem with OrmLite on Android.
When I increment the database version, the onUpgrade method is called as expected in my OrmLite Helper. After the upgrade, the onCreate method is called and I get this exception:
11-24 10:09:45.720: ERROR/AndroidConnectionSource(390): connection saved
com.j256.ormlite.android.AndroidDatabaseConnection#44f0f478 is not the one
being cleared com.j256.ormlite.android.AndroidDatabaseConnection#44f5d310
I have no clue why the cleared connection is not the same as the saved one.
I've put also my database functions (insert...) into the OrmLite Helper class. Maybe this could be a problem?!?
A snippet from my helper class:
public class OrmLiteDBProvider extends OrmLiteSqliteOpenHelper
implements IEntityProvider, IDBProvider {
//snip
#Override
public void onCreate(SQLiteDatabase db, ConnectionSource connectionSource) {
try {
Log.i(OrmLiteDBProvider.class.getName(), "Creating database and tables");
TableUtils.createTable(connectionSource, OrgManaged.class);
} catch (SQLException e) {
Log.e(OrmLiteDBProvider.class.getName(),
"Can't create database and tables", e);
throw new RuntimeException(e);
}
}
#Override
public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource,
int oldVersion, int newVersion) {
try {
Log.i(OrmLiteDBProvider.class.getName(),
"Database version changed. Dropping database.");
TableUtils.dropTable(connectionSource, OrgManaged.class, true);
// after we drop the old databases, we create the new ones
onCreate(db);
} catch (SQLException e) {
Log.e(OrmLiteDBProvider.class.getName(), "Can't drop databases", e);
throw new RuntimeException(e);
}
}
I think it's something simple I'm missing.
Thanks in advance for your effort.
Ok, I see the problem and it exists, unfortunately, in the sample program as well. In the ORMLite helper class, the onUpgrade method should use:
onCreate(db, connectionSource);
instead of the following which is calling the subclass:
onCreate(db);
I've reproduced this problem in the HelloAndroid example program which has been fixed. I've also fixed this properly in the OrmLiteSqliteOpenHelper base class in the Android side of the ORMLite code. Sorry for the problem.