In my already created and deployed application, I've created a database MainDB, using a single class file which extended SQLiteOpenHelper, viz.
public class BaseSQLiteOpenHelper extends SQLiteOpenHelper {
private final static String DATABASE_NAME = "MainDB";
....
....
}
Issue is I've tied this class, too much to a particular functionality.
Now I'm adding a totally new module in application, which will also interact with DB, but with different new tables.
Issue is I can't use the same class, as it is conflicting in more than one way. And even if I redesign the code, it will only add complexity from functional/understanding point of view.
So, I've decided to use same DB, but different tables.
Now I've already created DB in BaseSQLiteOpenHelper class.
So, how can I create new tables in seprate class using same DB?
One approach is to use separate Database as well, Or,
Create my new table in onCreate() in BaseSQLiteOpenHelper class only (issue with this is mentioning new table in same class seems awkward, as this class has nothing to do with my new table).
Please suggest.
Thank You
First check the current database version for this database
private final static String DATABASE_NAME = "MainDB";
private static final int DATABASE_VERSION = 1;
public BaseSQLiteOpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
and increment the database version(DATABASE_VERSION), and add your new table query in on Upgrade and oncreate method like below.
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("old query no need to change");
db.execSQL("Create your new table here");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < 2) {
db.execSQL("Create your new table here as well this for update the old DB");
}
}
Done!!!
Related
I have created a database with a table.I want to add more tables dynamically to that database on the user's command.
The onOpen() method is not useful as it also changes my previous tables that already exist in the database.
I assume you are using SQLite database. If that is the case, a working solution exists here:
Create new table in existing DB in separate SQLiteOpenHelper class.
see rmkrishna's answer from that post, below:
First check the current database version for this database
private final static String DATABASE_NAME = "MainDB";
private static final int DATABASE_VERSION = 1;
public BaseSQLiteOpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
and increment the database version(DATABASE_VERSION), and add your new table query in on Upgrade and oncreate method like below.
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("old query no need to change");
db.execSQL("Create your new table here");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < 2) {
db.execSQL("Create your new table here as well this for update the old DB");
}
}
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 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.
Is it better to have a single big SQLiteOpenHelper subclass that defines onCreate and onUpgrade methods for every table in the database, or is better to have many SQLiteOpenHelper subclasses, one for each table?
Is there a best practice? Or are both acceptable, but with different good and bad side effects?
You should have a single SQLiteOpenHelper class for all the tables. Check this link.
Just for the sake of a different approach:
You can always overried on the onOpen(..) method have it called your onCreate(..) . Be sure to use the "CREATE TABLE IF NOT EXISTS..." statement rather than "CREATE TABLE"
#Override
public void onOpen(SQLiteDatabase db) {
onCreate(db);
}
#Override
public void onCreate(SQLiteDatabase db) {
String CREATE_FRIENDS_TABLE = "CREATE TABLE IF NOT EXISTS ...";
db.execSQL(CREATE_FRIENDS_TABLE);
}
You do that with every class that extends from SQLiteOpenHelper
#TheReader is right. I prefer a single SQLiteOpenHelper for all tables, here is what i do: pass a List of "table creation" sqls to the Constructor of the SQLiteOpenHelper subClass, then in the onCreate function iterate the list to create each table.
so my SQLiteOpenHelper subclass looks sth like this:
public ModelReaderDbHelper(Context context, List<String> createSQLs, List<String> deleteSQLs){
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.TABLE_CREATION_SQLS = createSQLs;
this.TABLE_DELETE_SQLS = deleteSQLs;
}
#Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
for(String oneCreation : TABLE_CREATION_SQLS){
sqLiteDatabase.execSQL(oneCreation);
}
}
But that comes another problem: after adding a new table, and install the new version of the app with an existing old one installed, the new table won't be created, because the existence of the old database will prevent the onCreate function from being called. So user has to uninstall the app first, and install the app completely. The DATABASE_VERSION helps, it seem android will not execute the onCreate function if and only if the a existin database with the same name and the same DATABASE_VERSION
I am writing an app that displays fun-facts (and the source they are from). The user can browse through the facts one by one.
Here is the design I thought of :
Create a table in SQLiteDatabase with a text column that stores the fun-fact and a second column that stores it's source. (not sure if this is the best way to go about doing it, but I want the app available even without the network)
My question is, when database is initially created on the device, should I manually populate the database from within the code, something like this pseodo-code:-
#Override
public void onCreate(SQLiteDatabase db) {
//Create the table
//Populate the table
//Insert statement 1
//Insert statement 2
//Insert statement 3
...
//Insert statement 500
}
Surely there must be a better method to create the initial database when the app is installed?
Are you certain that you really need a databse? Doesn't it just add unnecessary overhead to something so trivial?
Can't you just declare the array in your code, or am I missing something? Whether it's in the db or your code, it is taking up space. The db will add some overhead to that and vious?will take some time to load, plus your code has to handle errors, etc.
Woudl you not be better off with a simple array declared in your code? Or am I misisng something obvious? (maybe users can d/l a new db? But is that so much more overhead than d/ling a new program?)
If I'm way off, please explain (rather than downvoting). I am trying to help
Edit: presumably you already have your facts soemwhere? Maybe in a text file? You could just write code to parse that and initialze and array (or populate a db). It should bascially be a short for loop.
use a class derived from SQLiteOpenHelper
i already wrote sth obout this on my blog www.xenonite.net
public class myDatabase extends SQLiteOpenHelper
{
private static final String DB_NAME = "database.db";
private static final int DB_VERSION = 1;
public MyDatabase(Context context)
{
super(context, DB_NAME, null, DB_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db)
{
db.execSQL("CREATE TABLE tbl_test ( id INTEGER PRIMARY KEY AUTOINCREMENT, test TEXT NOT NULL )");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
db.execSQL("DROP TABLE IF EXISTS tbl_test");
onCreate(db);
}
}
you can use this like
myDatabase db = new myDatabase(getApplicationContext());
sql = "INSERT INTO tbl_test (test) VALUES ('xyz')";
db.getWritableDatabase().execSQL(sql);
String sql = "SELECT id FROM tbl_test";
Cursor result = db.getWritableDatabase().rawQuery(sql, null);
int value;
while(result.moveToNext())
{
value = result.getInt(0);
}
on every call to db, myDatabase.onCreate() is called, so your database will be created on the first run. when changing the table structure, implement onUpgrade() and increment DB_VERSION