Foremost, I'm an Android developer and SQLite noob -- I've only done a few very simple apps as well as worked with SQL, MySQL, and related DBMSs but not SQLite before.
I'm trying to implement a database, decided to utilize Room with a pre-populated DB file -- using DB Browser for SQLite to create, update the file. One of the problems is I receive errors complaining the schemas don't match ("expected", "found"). Initially, I had mistakenly chosen data types not compatible with Room. I changed them, some even accidentally -- darn auto-selected drop-down menus -- but ultimately fixed them all.
Here's the comparison...
Expected:
TableInfo{name='Ingredient', columns={unit_system=Column{name='unit_system', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, amount=Column{name='amount', type='REAL', affinity='4', notNull=true, primaryKeyPosition=0, defaultValue='null'}, recipe_id=Column{name='recipe_id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, ingredient_id=Column{name='ingredient_id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1, defaultValue='null'}, unit_size=Column{name='unit_size', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, prep_type=Column{name='prep_type', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, food_id=Column{name='food_id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[ForeignKey{referenceTable='Food', onDelete='NO ACTION', onUpdate='NO ACTION', columnNames=[food_id], referenceColumnNames=[id]}, ForeignKey{referenceTable='Recipe', onDelete='NO ACTION', onUpdate='NO ACTION', columnNames=[recipe_id], referenceColumnNames=[id]}], indices=[]}
Found:
TableInfo{name='Ingredient', columns={unit_system=Column{name='unit_system', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, amount=Column{name='amount', type='NUMERIC', affinity='1', notNull=true, primaryKeyPosition=0, defaultValue='null'}, recipe_id=Column{name='recipe_id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, ingredient_id=Column{name='ingredient_id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1, defaultValue='null'}, unit_size=Column{name='unit_size', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, prep_type=Column{name='prep_type', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, food_id=Column{name='food_id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
I've tried:
deleting the file from the project, restarting Android Studio, then pasting the newer one
editing it as a text file in Android Studio
deleting the file from the project, Invalidate Caches / Restart, then paste the newer one
deleting the file, recreate the database from scratch, add it back to the project assets
Here are the CREATE statements from DB Browser:
CREATE TABLE "Food" (
"id" INTEGER,
"name" TEXT NOT NULL,
PRIMARY KEY("id" AUTOINCREMENT))
CREATE TABLE "Ingredient" (
"ingredient_id" INTEGER,
"amount" REAL NOT NULL,
"unit_size" TEXT,
"prep_type" TEXT,
"food_id" INTEGER NOT NULL,
"recipe_id" INTEGER NOT NULL,
"unit_system" TEXT NOT NULL,
PRIMARY KEY("ingredient_id" AUTOINCREMENT))
CREATE TABLE "Recipe" (
"id" INTEGER,
"name" TEXT NOT NULL,
"category" TEXT NOT NULL,
"media" TEXT NOT NULL,
"servings_amt" INTEGER NOT NULL,
"servings_type" TEXT NOT NULL,
"directions_us" TEXT NOT NULL,
"directions_metric" TEXT NOT NULL,
"tags" TEXT,
"favorite" INTEGER DEFAULT 0,
PRIMARY KEY("id" AUTOINCREMENT))
Here's what appears in Android Studio (auto opens after pasted)
SQLite format 3 # .G�
� �9
�� �!!�tableIngredientIngredientCREATE TABLE "Ingredient" (
"ingredient_id" INTEGER,
"amount" REAL NOT NULL,
"unit_size" TEXT,
"prep_type" TEXT,
"food_id" INTEGER NOT NULL,
"recipe_id" INTEGER NOT NULL,
"unit_system" TEXT NOT NULL,
PRIMARY KEY("ingredient_id" AUTOINCREMENT)
)�_�tableRecipeRecipeCREATE TABLE "Recipe" (
"id" INTEGER,
"name" TEXT NOT NULL,
"category" TEXT NOT NULL,
"media" TEXT NOT NULL,
"severings_amt" INTEGER NOT NULL,
"servings_type" TEXT NOT NULL,
"directions_us" TEXT NOT NULL,
"directions_metric" TEXT NOT NULL,
"tags" TEXT,
"favorite" INTEGER NOT NULL,
PRIMARY KEY("id" AUTOINCREMENT)
)P++Ytablesqlite_sequencesqlite_sequenceCREATE TABLE sqlite_sequence(name,seq)s�ItableFoodFoodCREATE TABLE "Food" (
"id" INTEGER,
"name" TEXT NOT NULL,
PRIMARY KEY("id" AUTOINCREMENT)
)
What am I doing wrong?
Thanks.
I'm not sure if I'm seeing this correctly or not, but...
Your Create SQL is
CREATE TABLE "Ingredient" (
"ingredient_id" INTEGER,
"amount" REAL NOT NULL,
"unit_size" TEXT,
"prep_type" TEXT,
"food_id" INTEGER NOT NULL,
"recipe_id" INTEGER NOT NULL,
"unit_system" TEXT NOT NULL,
PRIMARY KEY("ingredient_id" AUTOINCREMENT))
Shouldn't it be
CREATE TABLE "Ingredient" (
"ingredient_id" INTEGER,
"amount" NUMERIC NOT NULL,
"unit_size" TEXT,
"prep_type" TEXT,
"food_id" INTEGER NOT NULL,
"recipe_id" INTEGER NOT NULL,
"unit_system" TEXT NOT NULL,
PRIMARY KEY("ingredient_id" AUTOINCREMENT))
Related
Expected:
TableInfo{name='role', columns={title=Column{name='title', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, id=Column{name='id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1, defaultValue='null'}}, foreignKeys=[], indices=[]}
Found:
TableInfo{name='role', columns={id=Column{name='id', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'}, title=Column{name='title', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
I'm trying to make migration and I don't understand where is the problem. I see title is the first row, but I do not understand why. In RoleRoom we can see directly it is on the second place... How to fix it? :)
#TypeConverters(RoomConverters::class)
#Entity(tableName = "role")
class RoleRoom(
#PrimaryKey val id: Int = 0,
val title: String
)
in Migration class
database.execSQL("CREATE TABLE IF NOT EXISTS `role` (`id` INTEGER, `title` TEXT, PRIMARY KEY(`id`))")
The issues are that Room expects non nullables to be NOT NULL. That is Int and String are not nullable. So Room expects
CREATE TABLE IF NOT EXISTS `role` (`id` INTEGER NOT NULL, `title` TEXT NOT NULL, PRIMARY KEY(`id`))")
Hence the expected has .... notNull=true .... notNull=true whilst the found has .... notNull=false .... notNull=false
However, rather than trying to interpret the #Entity annotated class, it is simpler to let Room do the work. That is if you
Create the #Entity annotated class(es) as required
Add the #Entity annotated class(es) to the entities parameter of the #Database annotated abstract class.
Compile the project (CTRL + F9).
From the Android View look for the java(generated) folder/directory, expand the directories and locate the class that is the same name as the #Database annotated class, but suffixed with _Impl.
Within the class, locate the createAllTables method, and you will find code that exceutes the SQL for creating the tables with EXACTLY the SQL that Room expects.
Note that the code for room_master_table should be ignored as Room will create the table and populate it itself.
Copy the respective SQL and use that.
Room 2.5.0-alpha02
I need the prepopulate one table data to the database , So I make a .db file only have one table which I need inflate the prepopulate data , The Android developer document told 2.4.0 + Room have auto migrate ,and So I not write the migrate code . But when I build and run app, the data not add to the app database.
DataBase.kt
I add the fallbackToDestructiveMigration , and the app db version is higher one than the .db file
#Database(
entities = [DetectAd::class, DetectResult::class, DetectItem::class],
exportSchema = false,
version = 2
)
#TypeConverters(Converter::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun detectItemDao(): DetectItemDao
companion object {
#Volatile
private var INSTANCE: AppDatabase? = null
fun getDatabase(context: Context): AppDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"app_db.db"
)
.createFromAsset("database/appDatabase2.db")
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
// return instance
instance
}
}
}
appDatabase2.db file
App db after run
The prepopulate data not inflate to the db
So, should I make a complete prepopulate .db file which struct 100% same like the app db struct, although I only want to prepoulate one table data? If not ,what i need do ?
Thanks for your help.
Additional remarks
When I make the app db version to one (same to file) , app hava a error tip:
java.lang.IllegalStateException: Pre-packaged database has an invalid schema: detectAd(com.sunbio.coagulation.data.db.entity.DetectAd).
Expected:
TableInfo{name='detectAd', columns={Ad4=Column{name='Ad4', type='TEXT', affinity='2', notNull=notNull, primaryKeyPosition=0, defaultValue='null'}, Ad3=Column{name='Ad3', type='TEXT', affinity='2', notNull=notNull, primaryKeyPosition=0, defaultValue='null'}, Ad6=Column{name='Ad6', type='TEXT', affinity='2', notNull=notNull, primaryKeyPosition=0, defaultValue='null'}, Ad5=Column{name='Ad5', type='TEXT', affinity='2', notNull=notNull, primaryKeyPosition=0, defaultValue='null'}, Ad8=Column{name='Ad8', type='TEXT', affinity='2', notNull=notNull, primaryKeyPosition=0, defaultValue='null'}, Ad7=Column{name='Ad7', type='TEXT', affinity='2', notNull=notNull, primaryKeyPosition=0, defaultValue='null'}, adNo=Column{name='adNo', type='INTEGER', affinity='3', notNull=notNull, primaryKeyPosition=1, defaultValue='null'}, sampleNo=Column{name='sampleNo', type='TEXT', affinity='2', notNull=notNull, primaryKeyPosition=0, defaultValue='null'}, time=Column{name='time', type='TEXT', affinity='2', notNull=notNull, primaryKeyPosition=0, defaultValue='null'}, Ad2=Column{name='Ad2', type='TEXT', affinity='2', notNull=notNull, primaryKeyPosition=0, defaultValue='null'}, Ad1=Column{name='Ad1', type='TEXT', affinity='2', notNull=notNull, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
Found:
TableInfo{name='detectAd', columns={}, foreignKeys=[], indices=[]}
at androidx.room.RoomOpenHelper.checkIdentity(RoomOpenHelper.kt:159)
at androidx.room.RoomOpenHelper.onOpen(RoomOpenHelper.kt:128)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onOpen(FrameworkSQLiteOpenHelper.java:326)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:409)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:298)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableOrReadableDatabase(FrameworkSQLiteOpenHelper.java:273)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.innerGetDatabase(FrameworkSQLiteOpenHelper.java:225)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getSupportDatabase(FrameworkSQLiteOpenHelper.java:183)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:133)
at androidx.room.SQLiteCopyOpenHelper.getWritableDatabase(SQLiteCopyOpenHelper.kt:71)
at androidx.room.RoomDatabase.inTransaction(RoomDatabase.kt:634)
at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.kt:430)
at com.sunbio.coagulation.data.db.dao.DetectItemDao_Impl.getAllName(DetectItemDao_Impl.java:270)
at com.sunbio.coagulation.ui.manager.DetectManagerFragment$getData$1$1.invokeSuspend(DetectManagerFragment.kt:196)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:749)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
In the image of the pre-populated database the table name is detectItem Room expects a table named detectAd (and more).
The pre-populated database MUST HAVE the same tables (others will be ignored) as Room expects. The tables MUST HAVE the same columns that Room expects.
see below re prePackagedDatabaseCallback as an alternative resolution.
e.g. You don't appear to have a column Ad4 in the image, so just renaming detectItem to detectAd will result in yet another Expect .... Found ... error.
What Room expects is determined by the #Entity annotated classes that are in the list of entities coded in the #Database annotation.
from the message/log Room expects a column named Ad4 that is a type of TEXT
I would suggest that after you have created the #Entity classes and specified them in the #Database annotated class via the entities parameters of the #Database` annotation that you then use the SQL that Room generates.
The SQl is generated when you compile (Make the project).
This SQL can be found in the generated java (visible via Android View) in the createAlltable method class that is named the same as the #Database annotated class but suffixed with _Impl.
You do not need to create the room_master_table as this will be created by Room.
So, should I make a complete prepopulate .db file which struct 100% same like the app db struct, although I only want to prepoulate one table data? If not ,what i need do ?
YES (unless:-)
the alternative could be to utilise the prePackagedDatabaseCallback, in which case you could create the tables and then copy data from the detectItem table (that should exist as the callback is called when after the pre-packaged database has been copied from the assets)
again I strongly suggest using the SQL generated when you compile the App, Room is very particular in what it expects.
The link given below, covers the steps of copying the generated SQL.
when the processing is finished in the callback then Room continues in it's attempt to open the database checking that the schema is as expected (i.e the end result MUST be a schema that Room expects).
you may find this Question/Answer useful if this is how you want to proceed.
note I'm unsure about how, or if, Room manages prepackaged with subsequent migrations. However, I would suggest that it would be most prudent to not use the callback, but to always alter the prepackaged database (i.e. change the asset file accordingly).
doing so has the added benefit of being a test of the migration (or at least the SQL aspect of the migration, which will typically be all of the migration).
I'm trying to migrate my Room db to the next version and I keep getting the same error:
java.lang.IllegalStateException: A migration from 1 to 2 was required but not found. Please provide the necessary Migration path via RoomDatabase.Builder.addMigration(Migration ...) or allow for destructive migrations via one of the RoomDatabase.Builder.fallbackToDestructiveMigration* methods.
The only difference between my database versions is that I have added a new column. The migration is handled like this:
#Database(
version = 2,
entities = [Note::class],
exportSchema = true)
abstract class AppDatabase : RoomDatabase() {
abstract fun noteDao(): NoteDAO
companion object {
fun build(context: Context) = Room.databaseBuilder(context, AppDatabase::class.java, "NotesDatabase")
.addMigrations(MIGRATION_1_2).build()
}
}
val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Notes ADD COLUMN image STRING")
}
}
I'm not sure if I have implemented that correctly. The error tells me that I have to somehow call .build(). I tried that in the activity using the database, but the error was the same so I removed that call.
How can I fix this?
It appears that you are not invoking the build function and probably have another means of building the database (invoking the databaseBuilder).
e.g. In an activity/fragment you have something like :-
class MainActivity : AppCompatActivity() {
lateinit var db: AppDatabase
lateinit var dao: NoteDAO
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = Room.databaseBuilder(this,AppDatabase::class.java,"NotesDatabase")
.allowMainThreadQueries()
.build()
dao = db.noteDao()
dao.getAllNotes()
}
}
This after changing the Note entity and increasing the version to 2 yields the results e.g. :-
java.lang.IllegalStateException: A migration from 1 to 2 was required but not found. Please provide the necessary Migration path via RoomDatabase.Builder.addMigration(Migration ...) or allow for destructive migrations via one of the RoomDatabase.Builder.fallbackToDestructiveMigration* methods.
Instead you need to invoke the AppDatabase's build function
So the above would become :-
class MainActivity : AppCompatActivity() {
lateinit var db: AppDatabase
lateinit var dao: NoteDAO
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = AppDatabase.build(this) //<<<<<<<<<< CHANGED
dao = db.noteDao()
dao.getAllNotes() // Forces database access/open
}
}
HOWEVER, you will then get the Expected/Found issue something like :-
2022-03-21 09:15:20.385 14533-14533/a.a.so71549033kotlinroommigration E/AndroidRuntime: FATAL EXCEPTION: main
Process: a.a.so71549033kotlinroommigration, PID: 14533
java.lang.RuntimeException: Unable to start activity ComponentInfo{a.a.so71549033kotlinroommigration/a.a.so71549033kotlinroommigration.MainActivity}: java.lang.IllegalStateException: Migration didn't properly handle: notes(a.a.so71549033kotlinroommigration.Note).
Expected:
TableInfo{name='notes', columns={noteText=Column{name='noteText', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, image=Column{name='image', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, noteId=Column{name='noteId', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'}}, foreignKeys=[], indices=[]}
Found:
TableInfo{name='notes', columns={noteText=Column{name='noteText', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, image=Column{name='image', type='STRING', affinity='1', notNull=false, primaryKeyPosition=0, defaultValue='null'}, noteId=Column{name='noteId', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'}}, foreignKeys=[], indices=[]}
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
This is because STRING, as far as room is concerned, is not a valid column type.
In the above you can see/extract that room expects :-
image=Column{name='image', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}
BUT Room found :-
image=Column{name='image', type='STRING', affinity='1', notNull=false, primaryKeyPosition=0, defaultValue='null'}
Room only accepts column types of INTEGER, REAL, TEXT and BLOB (even though SQLite is far more flexible with column types).
The type depends upon the type of the variable, furthermore Room is also very specific about other parts of the definition, such as whether or not NOT NULL should be part and whether or not DEFAULT should be part of the definition or not.
However, Room allows you to ascertain exactly what the column definition should be. If you make the changes to the entity(ies) and compile the project then java code is generated by Room, this includes the SQL used to create the table(s) and within this SQL are the expected column definitions.
From the Android Studio Project View you will see Java (generated), within the classes/files under this will be some classes one of which will be AppDatabase_Impl. Within this class there will be a method createAlltables. Within this method is the SQL for all the tables.
e.g. :-
Note the image column, in this case, was coded as var image: String
String equates to TEXT and also NOT NULL. String? would not have NOT NULL
However, if ALTERing a table and adding a column with NOT NULL then SQLite requires that a DEFAULT is provided that is not null, as per:- f a NOT NULL constraint is specified, then the column must have a default value other than NULL. https://www.sqlite.org/lang_altertable.html
So in the case above then for the found to be what room expects then the ALTER SQL should be :-
ALTER TABLE Notes ADD COLUMN image TEXT NOT NULL DEFAULT 'unknown'
'unknown' could be whatever suits
I am trying to implement Room library and i have NUMERIC data type in my SQLite database. I tried to use Double because the value could have decimal points, but I get the error Migration didn't properly...
#ColumnInfo(name = "data")
var data: Double = 0.toDouble(),
Error message:
data=Column{name='data', type='REAL', affinity='4', notNull=true, primaryKeyPosition=0},
data=Column{name='data', type='NUMERIC', affinity='1', notNull=true, primaryKeyPosition=0},
How to implement NUMERIC type in Room?
I am scratching my head with this error. I couldn't find any answer so far. I have old database which I am migrating to Persistence Room library. However whenever I do migration, I am getting following error,
java.lang.IllegalStateException: Migration didn't properly handle.
Code I am using is as follows:
#Entity(tableName = ROUTE_TABLE)
public class RouteData {
static final String ROUTE_TABLE = "name";
#PrimaryKey(autoGenerate = true)
#ColumnInfo(name = "id")
private int id;
#ColumnInfo(name = "col1")
private String col1;
//Other columns with exactly same as 'col1' just different names
//Getters and Setters
}
For migration,
Room.databaseBuilder(context.getApplicationContext(), MyData.class, DATABASE_NAME)
.addMigrations(MIGRATION_LATEST)
.fallbackToDestructiveMigration()
.build();
private static final Migration MIGRATION_LATEST = new Migration(9, 10) {
#Override
public void migrate(SupportSQLiteDatabase db) {
//Log.i("Tag" , "Migration Started");
//Migration logic
//Log.i("Tag" , "Migration Ended");
}
};
When I run program. I get "Migration Ended" log in my LogCat but when I am trying access database again, it is giving me following error.
Caused by: java.lang.IllegalStateException: Migration didn't properly handle xxx.
Expected:
TableInfo{name='name', columns={col1=Column{name='col1', type='TEXT', notNull=false, primaryKeyPosition=0}, ....}, foreignKeys=[]}
Found:
TableInfo{name='name', columns={col1=Column{name='col1', type='INTEGER', notNull=false, primaryKeyPosition=0}, ....}, foreignKeys=[]}
I have no idea where where this "INTEGER" is coming. I tried uninstalling, invalidating cache and any other closely related solution. Any idea what is going on? It works perfectly fine if you freshly install app. Error is coming up only after migration. According to my log cat, all migration steps seems to be completed but it is still showing migration not handled properly.
Thank you all for trying to help me, however I have finally found the answer after days of frustrating debugging. In my app manifest auto backup was on,
android:allowBackup="true"
So while trying out various databases, google was actually backing up my any newly created databases and their structure and restoring them automatically when I was reinstalling app. Hence I was getting this wired error. Once I switch of auto backup android:allowBackup="false" and reinstall app, I can test migration properly.
My suggestion for all developers in future encountering such problem, SWITCH OFF auto backup while development. You can switch it on once you have tested your migration.
The main problem in your migration script is bellow:
Caused by: java.lang.IllegalStateException: Migration didn't properly handle xxx.
Expected:
TableInfo{name='name', columns={col1=Column{name='col1', type='TEXT', notNull=false, primaryKeyPosition=0}, ....}, foreignKeys=[]}
Found:
TableInfo{name='name', columns={col1=Column{name='col1', type='INTEGER', notNull=false, primaryKeyPosition=0}, ....}, foreignKeys=[]}
Here, in your Entity Class you have :
#ColumnInfo(name = "col1")
private String col1;
but in your migration query you may be adding col1 as INTEGER
From your error :
Expected :
columns={col1=Column{name='col1', type='TEXT', notNull=false, primaryKeyPosition=0}
Found :
columns={col1=Column{name='col1', type='INTEGER', notNull=false, primaryKeyPosition=0}
Solution: change your migration query like :
ALTER TABLE 'YOUR_TABLE' ADD COLUMN 'col1' TEXT
It will solve your problem.
Thanks :)