My Android App use SQLite database as an asset.
I deliver a .db file in /assets directory to provide both read-only tables and read/write tables.
When the user uses the App, it's datas are stored in read/write tables.
Sometimes I need to modify the schema of the database by adding a column in a table for example.
So I need to deliver a new .db file in the release.
If i do this the problem is that the user loses his data.
Is there a way to export/import the user data when he updates the App on his devise ?
I didn't find anything about this issue on the Web.
The standard way of handling this is, assuming that you are using (extending) the SQLiteOpenHelper class, is to utilise the version number in conjunction with overriding the onUpgrade method to ALTER the schema of the existing database, thus retaining the existing data.
version int: number of the database (starting at 1); if the database is older, onUpgrade(SQLiteDatabase, int, int) will be used to upgrade the database; if the database is newer, onDowngrade(SQLiteDatabase, int, int) will be used to downgrade the database
The SQLiteOpenHelper (or if using SQliteAssetHelper which extends SQLiteOPenHelper), when opening the database (if it exists) compares the coded version number against the version number stored in the header of the database. If the coded version number is greater than the stored version number then the onUpgrade method is called which is passed three parameters,
the SQLiteDatabase
the old (stored) version number as an int
the new (coded) version number as an int
You would typically check old and new and have code that makes the changes (ALTER TABLE or an alternative if the limitations of the ALTER TABLE force to do something like rename the original table, CREATE the changed table with the correct name, copy the existing data from the original table to the new table and finally DROP the renamed original table )
If the App is installed for a new user then that is when the asset will be copied. Thus covering both scenarios.
If not using an extension of SQLiteOpenHelper, then you can mimic using the stored version number by reading 4 bytes at offset 60 and comparing this to a coded version or even by copying the asset and getting the asset's version number, which would be managed with whatever tool you use to maintain the asset (e.g. via the user_version PRAGMA)
SQLite Database Header
Related
i`m still new to android programming, i usually code using Android Studio, here is my question about SQL lite
how do you accsess your database from your android phone?
where do you put your .db file ? some says i need to put it inside the assests folder
i often come through some tutorial where they put database name, create table, drop table query inside the sqllitehelper, why do they
put it again?
after you create the database in DB browser for sqlite software what did you do?
this is a question about android programming, i often come through some tutorial about crud or something related to database but i
dont see any INSERT INTO QUERY
do you need xampp for local server or what?
how do you accsess your database from your android phone?
If using the Android SDK, you'd typically have a Database Helper (subclass of SQLiteOpenHelper, if the database is a pre-existing database then SQLiteAssetHelper will copy the database file from the assets folder).
Note the above assumes the intended use of SQLite as an embedded database, if you want to share a database across multiple devices then SQLite would probably not be the database of choice (Firebase may be suitable).
.
where do you put your .db file ? some says i need to put it inside the
assests folder
As above, if it's a pre-existing database then the assets folder (in the case of SQLiteAssetHelper) will copy the database to the normally used /data/data//databases/ folder.
The asset file is compressed and read only so the App would copy the file to a usable folder, typically as above.
P.S. the file doesn't have to have any file extenstion or could have any valid file extenstion. Nothing that the file name MUST be the same as the database name, as that is the file that will be opened.
.
i often come through some tutorial where they put database name,
create table, drop table query inside the sqllitehelper, why do they
put it again?
This would typically be seen in the onUpgrade method.
What happens with the SQLiteOpenHelper subclass is that if the database doesn't exist, then the database is created and is from your perspective empty.
actually for android at least two system tables will exist;
1) sqlite_master which is a table of the tables and other items aka the schema, and
android_metadata which contains the locale
After the database is created the onCreate method is called and typically the tables (and possible other items, indexes, triggers, views) will be created using appropriate SQL generally invoked by using the SQLiteDatabase execSQL method.
The database is NOT created just by instantiating the helper an attempt (implied or explicit) has to be made to open the database, it is then that the database is checked for it's existence and created.
As such adding, for example, another table is NOT simply a case of adding more the onCreate method, as it will not run.
As such the SQLiteOpenHelper includes a means, by the way of the 4th parameter, the version number to facilitate upgrading the database (e.g. adding the new table).
The version number is stored in the database header and is checked by SQLiteOpenHelper against the value passed. If the value passed is greater than the stored value then onUpgrade is called.
if the value is less then onDownGrade is called and there which will result in an exception should the onDownGrade method not be coded in the sub-class of SQLiteOpenHelper.
Often, onUpgrade will DROP (delete) the tables and then call onCreate to create them and that is what you have seen (probably).
Note ANY EXISTING DATA WILL BE LOST
to not lose data you would use more complicated/in-depth code.
.
after you create the database in DB browser for sqlite software what
did you do?
Copy the file into the assets/database folder (if using SQLiteAssetHelper) or sometimes just into the assets folder.
You may have to create the assets folder and therefore also the database folder.
I would personally recommend closing DB Browser, opening it again, checking the data is as expected and then closing it again before copying the file.
this is a question about android programming, i often come through
some tutorial about crud or something related to database but i dont
see any INSERT INTO QUERY
The android SDK has many convenience methods, that build the SQL on you behalf, including (if the parameters are used accordingly) escaping arguments as required and protecting against SQL injection. Use of the convenience methods is recommended.
Here's an example of what you could instead see (to INSERT) :-
public long addUserReg(long studentId, String course) {
ContentValues cv = new ContentValues();
cv.put(COL_USERREG_STUDENT_ID,studentId);
cv.put(COL_USERREG_COURSE,course);
return mDB.insert(TBL_USERREG,null,cv);
}
The method is passed two values.
A ContentValues object is instantiated (consider this as a list of tuples with a key (name which correlates to the respective COLUMN name) and the value to be placed into that column).
A COLUMN value pair is added to the cv (an instance of a ContentValues object) COL_USERREG_STUDENT_ID holds the column name.
Another value pair is added to cv.
note you can consider cv as intelligent e.g. if you pass a byte array then the respective code for adding a BLOB is generated.
The insert convenience method is invoked, assuming COL_USERREG_STUDENT_ID resolves to studentid and COL_USERREG_COURSE resolves to course and TBL_USERREG resolves to course_table then the resultant SQL would effectively be INSERT OR IGNORE INTO course_table (studentid,course) VALUES('1','3') (assuming the studentid value passed was 1 and the course value was 3).
do you need xampp for local server or what?
No (I beleieve XAMPP is for Apache (server) MYSQL not SQLITE PHP along with PHPMYADMIN) but see above about SQLite being intended as an embedded database not a client/server type database. See Appropriate Uses For SQLite
I would like to know if it is possible to recover the old database data after upgrading to new database version of Android SQLite?
Thank you.
You cannot get the previous version database data because now it is upgraded.
You can take backup of each version before doing upgrade
Refer this :
Backup/restore sqlite db in android
Not if any of the old data has been changed (unless you can easily determine what has been changed and you can undo the changes).
It is possible to change the version number back using PRAGMA user_version = ?, where ? is an integer representing the version number to be changed to. This literally only changes that value (Offset 60 in the DB header). user_version pragma. If changing the the actual stored version number, then you would have to consider the coded version number as used by the super call, if they differ then onUpgrade or onDownGrade would be called. That is the value as stored in the DB header is compared to the value provided in the code by the super call.
You could alternatively change the version number passed to the Database Helper (subclass of SQLiteOpenHelper) BUT this would result in an exception unless the onDownGrade method was Overridden.
However, this method is not abstract, so it is not mandatory for a
customer to implement it. If not overridden, default implementation
will reject downgrade and throws SQLiteException. onDowngrade
The version number, as stored in the database, has no influence itself over the data. It's really a convenience value and it just so happens that SQLiteOpenHelper makes use of the value.
The database itself is just a file to back it up you just copy the file to restore it you basically copy it back. However, implementing backup and restore will only be of use after it has been implemented.
I have a dilemma regarding a free app that I allow users to import their data (an sqlite file on the SD card) to a paid app.
After doing these updates; I realized that if I need to make future changes to the database, the user will need to import the same DB version (from the free app) to the existing version (of the paid app).
Real life example:
Let's say version 1 of both apps has 1 table with 5 columns. I do an upgrade to v2, now the 1 table has 6 columns.
When a potential user does an import within the paid app to bring in data from the free app, there is a chance that the free app can be on DB version 1 (if user didn't update app recently) while the paid app would be looking for DB version 2. This I assume leads to a crash on startup.
How can I do a check like this in the paid app before doing import: (pseudo code)
File olddb = oldDb.db; // get the back up file here from SD
int piadAppDBVersion = 2; // check for the current version of the database in paid app
if (olddb.getDatabaseVersion() == getPaidAppDBVersion()) { // made up functions
// allow import;
} else {
// Toast "Your databases are incompatible"
}
So the two questions:
1. If the above code is an appropriate solution to ensure compatibility, how can this be done?
2. If the above is not a standard solution to my problem, then what is?
Side note: My import consists of a simple file copy: copying a backcup db on external storage and overwriting the db on internal storage.
Consider a "version" or "feature" table in the SQLite Database. Do not be afraid to incorporate this as part of a stable schema; many of my database schemas contain journals of applied scripted changes.
However, SQLite does support PRAGMA user_version which can also be used for this purpose, albeit it can only store a single integer value:
The pragmas schema_version and user_version are used to set or get the value of the schema-version and user-version, respectively. The schema-version and the user-version are big-endian 32-bit signed integers stored in the database header at offsets 40 and 60, respectively.
The schema-version is usually only manipulated internally by SQLite ..
The user-version is not used internally by SQLite. It may be used by applications for any purpose.
The user_version PRAGMA is supported via the standard Android SQLite API which can be accessed with SQLiteDatabase.getVersion and setVersion; after the database has been opened.
See also Where does Android store SQLite's database version?
SQLiteDatabase sqlDb = SQLiteDatabase.openDatabase
(db.getPath(), null, SQLiteDatabase.OPEN_READONLY);
if (sqlDb.getVersion()>DBConnect.version)
{
//you have to update app to the last version first
}
In my android app, I was using a standard SQLite database with a helper class that had 1 table with 3 columns. In the most recent update I had to add another column of to the table, but some users have reported crashes, which (judging by the stack trace) I think comes from the new version trying to read from a column that does not exist because the data is from the old version. How can I protect the users' data between updates short of a manual backup and restore?
Here is the link to the complete updated database class:
https://github.com/cjbrooks12/scripturememory/blob/working/src/com/caseybrooks/scripturememory/databases/VersesDatabase.java
SQLiteOpenHelper will handle the database versioning, you will just have to provide it with proper database version numbers and overridden callbacks. Looking at your code:
Your DB_VERSION is 1. When you change the database schema between released versions, you should increment this number. The version number is stored in the database file, and if the version provided in code is different from the one stored in file, onUpgrade() or onDowngrade() will be called accordingly. In your case, since the database file already exists, no onCreate() was called and since the version numbers matched, no upgrade was performed.
Your onUpgrade() drops the table and then recreates it. In some cases this might be ok, say, it's just a cached copy of data stored elsewhere, but usually as a user, I don't want an app upgrade to delete my data. Implement onUpgrade() so that it does the necessary schema modifications while preserving data. Some generic strategies for this:
If it's just adding some columns ALTER TABLE and put some suitable default values.
If it's more complex schema change, rename the old tables to temporary names, create new tables and then migrate data from the temp tables.
In any case, after onUpgrade() the database schema should be in the same shape it would be if onCreate() was called to create a new database, but with existing data preserved.
I have the following scenario:
My app is published with database version 4 to the customers.
I did some bugfixes and added some more features. This process also changed my models and thats why the database changed too.
How can I check what database version the customer has installed on his devices and migrate the old data to the new database? Is there an onUpgrade method or something like this in the ActiveAndroid Library?
After taking a deeper look into ActiveAndroid's sourcecode I found a solution.
ActiveAndroid can use sql-scripts located in your asset folder to migrate from one version to another.
It sorts all your sql files located in assets/migrations/ using a natural sorting algorithm:
Each SQL script which was found will be executed if its > oldVersion and <= newVersion
if you access your db via SQLiteOpenHelper and do proper db versioning than you can use it's onUpgrade method to run some code to update your db. Othewise you should do your custom solution.
I suggest that you create a class which extends SQLiteOpenHelper. When your database is opened through this class, it will automatically call the onUpgrade() method when necessary. The parameters to this method include the new and old version numbers of your database schema.
Whenever your schema changes you need to increment the database version number, either through Configuration or AA_DB_VERSION meta-data. If new classes are added, ActiveAndroid will automatically add them to the database. If you want to change something in an existing table however (e.g. add or delete a column), this is done using sql-scripts named <NewVersion>.sql, where NewVersion is the AA_DB_VERSION, in assets/migrations.
ActiveAndroid will execute a script if its filename is greater than the old database-version and smaller or equal to the new version.
Let’s assume you added a column color to the Items table. You now need to increase AA_DB_VERSION to 2 and provide a script 2.sql.
ALTER TABLE Items ADD COLUMN color INTEGER;