i have developed a tutorial app in which i have saved more than 500 questions and answers.
their is one more table called favourites. which is for user input.
now, i want to update my app with new questions and answers.
but i dont want to erase the data of favourites table (in case, user has marked some questions favourites, so those questions should not be erased from favourites)
so how can i do it?
because, i have used SQLassethelper library for database connectivity.
my old db contains:
data table(static table)
favourites table(local table)
so, according to sqliteassethelper documentation i added my new db:
that contains: updated data table. i didnt inserted favourites table here coz it will be created in script file.
and stored that db in assets>>databases folder.
then
i created a script fild
db.db_upgrade_1-2.sql
alter table "favourites" rename to "favourites_tmp";
create table "favourites" (
"id" Integer not null primary key autoincrement unique,
"question" text,
"answer" text,
"category" text,
"catid" integer
);
insert into "favourites" ("id","question","answer","category","catid") select from "favourites_tmp" "id","question","answer","category","catid" from "favourites_tmp";
drop table "favourites_tmp";
so i think here favourites table will be created with old data.
but
when i run the project, it says: no such tabld favourites.
The documentation tells you to
create a text file containing all required SQL commands to upgrade the database from its previous version to it's current version.
You can use any SQL commands, not only ALTER TABLE, but also INSERT.
The database file in the assets folder is used only if there is no old data (if the app is installed for the first time). If there is old data, SQLiteAssetHelper executes the SQL upgrade script instead.
The SQLiteAssetHelper project contains an example that shows how such a script would look like.
To keep the data in the favourites table, you do not need to do anything.
To add the new question/answers, use a bunch of INSERT statements.
(For how to get those INSERT statements, see How to compare two SQLite databases.)
finally i got answer for my questions.
as i said i am using SQLiteAssetHelper library.
and now i want to add new records and want to release the update version.
so i was finding the feature by which i can store new updated db in assets folder. and this library will update the old db in user's phone. with keeping particular table in old db.
but currently this library doesnt offers such feature.
the upgrade script can be use only to make changes is old db. we can add new updated db and copy the data from new one.
if we want to add new data and also dont want to erase local data table.
then we need to write insert queries in upgrade script as described in documentation of that library.
but if we have to add 100 queries then their is no shortcut for it.
we have to write 100 insert statements in upgrade script.
and in case if we gate a error saying
cannot upgrade read only database from version x to y then
here is the solution for it:
SQLITE cant upgrade read-only database from version 1 to 2
Related
We have an Android app, which is using read/ write data using Android Room database library, and then download/ upload to cloud storage.
Now, we are developing an iOS app, which is suppose able to read/ write the data.
There is no issue for our iOS app to read SQLite file written by Android Room database, because we are the one who define database schema.
However, there are issue, for iOS app to write an Android Room database library compatible SQLite file. We notice Android Room database library is expecting the following 3 additional tables.
CREATE TABLE room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT);
CREATE TABLE android_metadata (locale TEXT);
CREATE TABLE sqlite_sequence(name,seq);
The sample data contain in the 3 additional tables are as follow.
INSERT INTO "main"."room_master_table" ("id", "identity_hash") VALUES ('42', '5471e2f102feee2750d42986836b0c42');
INSERT INTO "main"."android_metadata" ("locale") VALUES ('en_US');
INSERT INTO "main"."sqlite_sequence" ("name", "seq") VALUES ('plain_note', '62');
INSERT INTO "main"."sqlite_sequence" ("name", "seq") VALUES ('attachment', '6');
INSERT INTO "main"."sqlite_sequence" ("name", "seq") VALUES ('tab_info', '5');
I think I am able to generate data for android_metadata & sqlite_sequence manually.
But, I am clueless in generating data for room_master_table.
I tested a SQLite file without room_master_table, it will cause the following error during reading via Android Room.
Caused by: java.lang.IllegalStateException: Room cannot verify the
data integrity. Looks like you've changed schema but forgot to update
the version number. You can simply fix this by increasing the version
number.
I was wondering, is there a way to generate SQLite file from iOS platform, which is compatible with Android Room database library? Or, it is simply not possible?
In short don't try to create the said tables, they are all system tables you should let them be created accordingly.
android_metadata just stores the locale and is created by the android SQLiteOpenHelper.
room_master_table stores a hash of the schema, if the hash doesn't match then you get Looks like you've changed schema but forgot to update the version number.. The hash is created at compile time.
sqlite_sequence exists if the AUTOINCREMENT keyword is used in a PRIMARY KEY definition. There is rarely any need to use AUTOINCREMENT. It is recommended to not use AUTOINCREMENT (Room's autogenerate = true). The table hold's a row per table that has AUTOINCREMENT. It stores the highest ever used rowid value. When a new row is inserted instead of just using the highest rowid to determine the next ( max(rowid) + 1), it instead uses the greater of the max(rowid) and the stored max ever allocated value and then adds 1. Thus it has to access the sqlite_sequence table to get the value and thus unless there is a need to always have a rowid greater than any ever allocated it is a waste.
If you use an SQLite database for both, and the IOS doesn't have sqlite_sequence then you should not have autogenerate coded anywhere in the #PrimaryKey annotation, as Room will then hit the Expected .... Found .... errors. As room is very particular about the schema.
I was wondering, is there a way to generate SQLite file from iOS platform, which is compatible with Android Room database library? Or, it is simply not possible?
Yes it is possible. In short don't create any of the tables, let Room create them. Then (assuming that both schemas are similar enough (data wise) have the same columns and column order). You can then load the Room tables from the SQLite file along the lines of
`INSERT INTO room_table_? SELECT * FROM ios_table_?;`
When and how frequently you do this will change exactly how you get to the stage when you can do the copy. If the schemas are identical and it's a one of then you could perhaps utilise the .createFromFile or if the schemas are close .createFromFile where you can modify the schema accordingly (if so then you might find this useful).
I have an Android app where I am using prepopulated database from assets.
I would like to know what is the best way to do migrations if I would like to keep user's data and also add any new records from prepopulated database if there are any. (I assume I need to compare records in device's database with prepopulated one)
I have tried fallbackToDestructiveMigration, but this method is just removing device's database and copying new one from assets. (So I am loosing user's data)
The standard migration approach is good, but I don't know how to check during migration if there are new records in prepopulated database and add them to the device's database after migration.
Thank you!
The fallbackToDestructiveMigration() method will destructively recreate database tables, ONLY IF the migrations steps that would migrate old database schemas to the latest schema version are not found.
Source: Room docs
In your case, lets say the pre-exisitng version of your DB is 1, and the new one you are going to provide is 2, then your migration steps from 1 to 2 can be as follows:
// Create a table for backup
CREATE TABLE myTable_backup(tableId VARCHAR,....);
// Copy old data to this backup table
INSERT INTO myTable_backup SELECT tableId,... FROM myTable;
// Delete old table
DROP TABLE myTable;
// Create the required table with new schema
CREATE TABLE myTable(tableId VARCHAR,....);
// Insert pre-existing data to your new schema
// Overwrite might / might not happen based on your Primary key strategy
INSERT INTO myTable SELECT tableId,... FROM myTable_backup;
// Delete the backup table
DROP TABLE myTable_backup;
The migration steps can be written as per this Room docs.
I am using Mozila extension SQLite Manager to create a database and use it in my app.
I created a table named test.
Then I read the data using the following line and it succeed.
My question is: "testing" should be the name of table right?
But when I use "select * from test" it reads nothing.
Initially I named the table as "testing".
Cursor cursor=dbHelper.QueryData("select * from testing");
It seems that you are indeed asking how to ship a prepopulated database in your app - or I don't see how could you use it in your app.
Now the steps are very simple:
1. If not already existing, copy the database from the assets folder to the data path.
2. Use it from there.
You will find some related posts on SO. For instance: here
and here
Now, if you changed your table name (!!), you must respect the new table name.
The new database must be copied in the assets folder, but the old database now must be removed from the the data path.
This is because otherwise the app will find the database and won't copy the new one over it.
Which is the desired behaviour: you don't want your app to copy the database each time it starts, but only once - since it's a time consuming operation.
I have already uploaded one apk file for one of the project, now i am updating apk with updated column in my database table,so i dont want to loss previous apk db table data.
so please help me out from this.
Thanks,
Dhiraj
Use SQLiteOpenHelper and implement onUpgrade(). You are passed the old and new database schema versions, and you can then perform an in-place modification of your database structure (e.g., run ALTER TABLE statements using execSql() on the supplied SQLiteDatabase instance).
I'm working on an Android application that use a DB sent in the assets folder. Periodically, I need to update one of the tables in the database, but without deleting the contents of the others (because they had data from the user).
I have read that increasing the version of DB will upgrade the entire DB, but that means resetting every single table.
Is there any way to achieve this?
You can handle it internally, I'm not sure what triggers your need to update the table, the initial setup of the app or later in your processing. The process is sort of rudimentary.
Let's say table A has data and you want to add 'col_new' to it.
DROP TABLE Temp
ALTER TABLE A RENAME TO Temp
Drop table A
Create table A with all the columns Table A has plus the 'col_new'.
Query table Temp and insert it into the A table something like this
insert into A (name, phonenumber) select name, address from Temp
Check that your counts match for both the tables. Set col_new as you may.
It's probably not what you wanted to hear, but I hope it helps.
I've finally done what CommonsWare recommended: to separate databases. I changed my design so right now I have two different databases (one containing the application information and the other containing the user information).
With this I'm able to update application DB without deleting user information.