Room Database Migration doesnt properly handle ALTER TABLE migration
Java.lang.IllegalStateException
Migration didn't properly handle
user(therealandroid.github.com.roomcore.java.User).
Expected:
TableInfo{name='user', columns={name=Column{name='name', type='TEXT',
notNull=false, primaryKeyPosition=0}, age=Column{name='age',
type='INTEGER', notNull=true, primaryKeyPosition=0},
id=Column{name='id', type='INTEGER', notNull=true,
primaryKeyPosition=1}}, foreignKeys=} Found:
Found
TableInfo{ name='user', columns={name=Column{name='name', type='TEXT',
notNull=false, primaryKeyPosition=0}, id=Column{name='id',
type='INTEGER', notNull=true, primaryKeyPosition=1},
age=Column{name='age', type='INTEGER', notNull=false,
primaryKeyPosition=0}}, foreignKeys=}
I'm trying to perform a simple migration, I have a class called User
and it have two columns ID (primary key)
and NAME TEXT
and then I populate database with two users data, then I add the column AGE
in the object User
and in the Migration constant I add an alter table
to add this new column and lastly I replace version of the database 1 to 2.
Here is the code
User.class
@Entity(tableName = "user")
public class User {
@PrimaryKey
private int id;
@ColumnInfo(name = "name")
private String name;
@ColumnInfo(name = "age")
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Database class
@Database(entities = {User.class}, version = 2)
public abstract class RoomDatabaseImpl extends RoomDatabase {
abstract UserDao userDao();
}
Migration code
public static Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'age' INTEGER");
}
};
and it call
Room.databaseBuilder(context, RoomDatabaseImpl.class, "Sample.db")
.addMigrations(MIGRATION_1_2)
.allowMainThreadQueries()
.build();
Before change the object adding AGE
and performing the migration I add two register and it works.
After performing the migration, I just tried to add a new User as bellow:
User user = new User();
user.setName("JoooJ");
user.setId(3);
user.setAge(18);
List<User> userList = new ArrayList<>();
userList.add(user);
App.database(this).userDao().insertAll(userList); // The crash happens here
Other informations:
Android Studio 3 and I didn't tested in the actual.
Dependencies:
compile "android.arch.persistence.room:runtime:1.0.0-alpha9-1"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0-alpha9-1"
compile "android.arch.persistence.room:rxjava2:1.0.0-alpha9-1"
gradle 2.3.3
Can someone help me please, I realy don't know what im doing wrong or if it is a bug.
android sqlite android-room
add a comment |
Java.lang.IllegalStateException
Migration didn't properly handle
user(therealandroid.github.com.roomcore.java.User).
Expected:
TableInfo{name='user', columns={name=Column{name='name', type='TEXT',
notNull=false, primaryKeyPosition=0}, age=Column{name='age',
type='INTEGER', notNull=true, primaryKeyPosition=0},
id=Column{name='id', type='INTEGER', notNull=true,
primaryKeyPosition=1}}, foreignKeys=} Found:
Found
TableInfo{ name='user', columns={name=Column{name='name', type='TEXT',
notNull=false, primaryKeyPosition=0}, id=Column{name='id',
type='INTEGER', notNull=true, primaryKeyPosition=1},
age=Column{name='age', type='INTEGER', notNull=false,
primaryKeyPosition=0}}, foreignKeys=}
I'm trying to perform a simple migration, I have a class called User
and it have two columns ID (primary key)
and NAME TEXT
and then I populate database with two users data, then I add the column AGE
in the object User
and in the Migration constant I add an alter table
to add this new column and lastly I replace version of the database 1 to 2.
Here is the code
User.class
@Entity(tableName = "user")
public class User {
@PrimaryKey
private int id;
@ColumnInfo(name = "name")
private String name;
@ColumnInfo(name = "age")
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Database class
@Database(entities = {User.class}, version = 2)
public abstract class RoomDatabaseImpl extends RoomDatabase {
abstract UserDao userDao();
}
Migration code
public static Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'age' INTEGER");
}
};
and it call
Room.databaseBuilder(context, RoomDatabaseImpl.class, "Sample.db")
.addMigrations(MIGRATION_1_2)
.allowMainThreadQueries()
.build();
Before change the object adding AGE
and performing the migration I add two register and it works.
After performing the migration, I just tried to add a new User as bellow:
User user = new User();
user.setName("JoooJ");
user.setId(3);
user.setAge(18);
List<User> userList = new ArrayList<>();
userList.add(user);
App.database(this).userDao().insertAll(userList); // The crash happens here
Other informations:
Android Studio 3 and I didn't tested in the actual.
Dependencies:
compile "android.arch.persistence.room:runtime:1.0.0-alpha9-1"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0-alpha9-1"
compile "android.arch.persistence.room:rxjava2:1.0.0-alpha9-1"
gradle 2.3.3
Can someone help me please, I realy don't know what im doing wrong or if it is a bug.
android sqlite android-room
A bit of a shot in the dark, but perhaps try"ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL DEFAULT 0"
(0 could be whatever you consider suitable).
– MikeT
Sep 22 '17 at 22:33
1
Room expects the column order to match the field order. It would appear that the results of theALTER TABLE
are resulting in a different order.
– CommonsWare
Sep 23 '17 at 11:36
Check bellow answer. It has complete description: stackoverflow.com/a/51245898/3073945
– Md. Sajedul Karim
Jul 9 '18 at 12:49
add a comment |
Java.lang.IllegalStateException
Migration didn't properly handle
user(therealandroid.github.com.roomcore.java.User).
Expected:
TableInfo{name='user', columns={name=Column{name='name', type='TEXT',
notNull=false, primaryKeyPosition=0}, age=Column{name='age',
type='INTEGER', notNull=true, primaryKeyPosition=0},
id=Column{name='id', type='INTEGER', notNull=true,
primaryKeyPosition=1}}, foreignKeys=} Found:
Found
TableInfo{ name='user', columns={name=Column{name='name', type='TEXT',
notNull=false, primaryKeyPosition=0}, id=Column{name='id',
type='INTEGER', notNull=true, primaryKeyPosition=1},
age=Column{name='age', type='INTEGER', notNull=false,
primaryKeyPosition=0}}, foreignKeys=}
I'm trying to perform a simple migration, I have a class called User
and it have two columns ID (primary key)
and NAME TEXT
and then I populate database with two users data, then I add the column AGE
in the object User
and in the Migration constant I add an alter table
to add this new column and lastly I replace version of the database 1 to 2.
Here is the code
User.class
@Entity(tableName = "user")
public class User {
@PrimaryKey
private int id;
@ColumnInfo(name = "name")
private String name;
@ColumnInfo(name = "age")
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Database class
@Database(entities = {User.class}, version = 2)
public abstract class RoomDatabaseImpl extends RoomDatabase {
abstract UserDao userDao();
}
Migration code
public static Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'age' INTEGER");
}
};
and it call
Room.databaseBuilder(context, RoomDatabaseImpl.class, "Sample.db")
.addMigrations(MIGRATION_1_2)
.allowMainThreadQueries()
.build();
Before change the object adding AGE
and performing the migration I add two register and it works.
After performing the migration, I just tried to add a new User as bellow:
User user = new User();
user.setName("JoooJ");
user.setId(3);
user.setAge(18);
List<User> userList = new ArrayList<>();
userList.add(user);
App.database(this).userDao().insertAll(userList); // The crash happens here
Other informations:
Android Studio 3 and I didn't tested in the actual.
Dependencies:
compile "android.arch.persistence.room:runtime:1.0.0-alpha9-1"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0-alpha9-1"
compile "android.arch.persistence.room:rxjava2:1.0.0-alpha9-1"
gradle 2.3.3
Can someone help me please, I realy don't know what im doing wrong or if it is a bug.
android sqlite android-room
Java.lang.IllegalStateException
Migration didn't properly handle
user(therealandroid.github.com.roomcore.java.User).
Expected:
TableInfo{name='user', columns={name=Column{name='name', type='TEXT',
notNull=false, primaryKeyPosition=0}, age=Column{name='age',
type='INTEGER', notNull=true, primaryKeyPosition=0},
id=Column{name='id', type='INTEGER', notNull=true,
primaryKeyPosition=1}}, foreignKeys=} Found:
Found
TableInfo{ name='user', columns={name=Column{name='name', type='TEXT',
notNull=false, primaryKeyPosition=0}, id=Column{name='id',
type='INTEGER', notNull=true, primaryKeyPosition=1},
age=Column{name='age', type='INTEGER', notNull=false,
primaryKeyPosition=0}}, foreignKeys=}
I'm trying to perform a simple migration, I have a class called User
and it have two columns ID (primary key)
and NAME TEXT
and then I populate database with two users data, then I add the column AGE
in the object User
and in the Migration constant I add an alter table
to add this new column and lastly I replace version of the database 1 to 2.
Here is the code
User.class
@Entity(tableName = "user")
public class User {
@PrimaryKey
private int id;
@ColumnInfo(name = "name")
private String name;
@ColumnInfo(name = "age")
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Database class
@Database(entities = {User.class}, version = 2)
public abstract class RoomDatabaseImpl extends RoomDatabase {
abstract UserDao userDao();
}
Migration code
public static Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'age' INTEGER");
}
};
and it call
Room.databaseBuilder(context, RoomDatabaseImpl.class, "Sample.db")
.addMigrations(MIGRATION_1_2)
.allowMainThreadQueries()
.build();
Before change the object adding AGE
and performing the migration I add two register and it works.
After performing the migration, I just tried to add a new User as bellow:
User user = new User();
user.setName("JoooJ");
user.setId(3);
user.setAge(18);
List<User> userList = new ArrayList<>();
userList.add(user);
App.database(this).userDao().insertAll(userList); // The crash happens here
Other informations:
Android Studio 3 and I didn't tested in the actual.
Dependencies:
compile "android.arch.persistence.room:runtime:1.0.0-alpha9-1"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0-alpha9-1"
compile "android.arch.persistence.room:rxjava2:1.0.0-alpha9-1"
gradle 2.3.3
Can someone help me please, I realy don't know what im doing wrong or if it is a bug.
android sqlite android-room
android sqlite android-room
edited May 2 '18 at 15:50
W.K.S
5,78275898
5,78275898
asked Sep 22 '17 at 19:34
diogojmediogojme
1,2801220
1,2801220
A bit of a shot in the dark, but perhaps try"ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL DEFAULT 0"
(0 could be whatever you consider suitable).
– MikeT
Sep 22 '17 at 22:33
1
Room expects the column order to match the field order. It would appear that the results of theALTER TABLE
are resulting in a different order.
– CommonsWare
Sep 23 '17 at 11:36
Check bellow answer. It has complete description: stackoverflow.com/a/51245898/3073945
– Md. Sajedul Karim
Jul 9 '18 at 12:49
add a comment |
A bit of a shot in the dark, but perhaps try"ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL DEFAULT 0"
(0 could be whatever you consider suitable).
– MikeT
Sep 22 '17 at 22:33
1
Room expects the column order to match the field order. It would appear that the results of theALTER TABLE
are resulting in a different order.
– CommonsWare
Sep 23 '17 at 11:36
Check bellow answer. It has complete description: stackoverflow.com/a/51245898/3073945
– Md. Sajedul Karim
Jul 9 '18 at 12:49
A bit of a shot in the dark, but perhaps try
"ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL DEFAULT 0"
(0 could be whatever you consider suitable).– MikeT
Sep 22 '17 at 22:33
A bit of a shot in the dark, but perhaps try
"ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL DEFAULT 0"
(0 could be whatever you consider suitable).– MikeT
Sep 22 '17 at 22:33
1
1
Room expects the column order to match the field order. It would appear that the results of the
ALTER TABLE
are resulting in a different order.– CommonsWare
Sep 23 '17 at 11:36
Room expects the column order to match the field order. It would appear that the results of the
ALTER TABLE
are resulting in a different order.– CommonsWare
Sep 23 '17 at 11:36
Check bellow answer. It has complete description: stackoverflow.com/a/51245898/3073945
– Md. Sajedul Karim
Jul 9 '18 at 12:49
Check bellow answer. It has complete description: stackoverflow.com/a/51245898/3073945
– Md. Sajedul Karim
Jul 9 '18 at 12:49
add a comment |
5 Answers
5
active
oldest
votes
The error message is hard to parse, but there's a difference:
TableInfo{name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, age=Column{name='age', type='INTEGER', notNull=true, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}}, foreignKeys=} Found:
Found
TableInfo{ name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}, age=Column{name='age', type='INTEGER', notNull=false, primaryKeyPosition=0}}, foreignKeys=}
Age is nullable but Room expected it to be not null.
Change your migration to:
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL");
Since this exception explanation is VERY difficult to parse, I have created a small script that does the diff for you.
Example:
mig "java.lang.IllegalStateException: Migration failed. expected:TableInfo{name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, age=Column{name='age', type='INTEGER', notNull=true, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}}, foreignKeys=} , found:TableInfo{name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}, age=Column{name='age', type='INTEGER', notNull=false, primaryKeyPosition=0}}, foreignKeys=}"
Result:
1
Works like a charm, thanks for helping. And now I understand, when you perform migrations, you must specify the DEFAULT value for the new column to be populated.
– diogojme
Sep 25 '17 at 17:43
Try your migrations on a dummy database and see if the query does what you expect it to do.
– Benoit Duffez
Sep 25 '17 at 18:40
For sure I will, thanks for the feedback.
– diogojme
Sep 25 '17 at 20:36
This doesnt work for me although it should..
– Ali Kazi
May 21 '18 at 1:54
1
I also found something interesting: if you created indices in your @Entity annotation in your model, you need to also do it in SQL in your migration script, for exampleCREATE INDEX
index_History_nodeId` ONHistory
(nodeId
)` and if you don't you'll get aMigration didn't properly handle
– Raphael C
May 31 '18 at 14:02
|
show 2 more comments
I too wrote a small JS script which you can find https://hrankit.github.io/RoomSQLiteDifferenceFinder/
The process is pretty Simple.
Input the Expected error log in Expected column which is the Left One.
Input the Found error log in Found column which is the Right One.
Press Go. button. The error logs get converted to JSON.
Press Compare button and Voila, you have the difference you need.
This plugin finds out the difference in the two Expected and Found dump from the Android Studio Logcat.
Checkout the image of comparison here
2
Whilst this may theoretically answer the question, it would be preferable to include the essential parts of the answer here, and provide the link for reference.
– Adriaan
Sep 1 '18 at 11:53
@HRankit Just Awesome, your script solved my problem.
– Ritesh Adulkar
Jan 9 at 15:32
add a comment |
None of the answers are correct in any of the links. After much experiments, found a way for it. The ALTER query needs to be written in the following way to make it work:
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL DEFAULT 0")
However, the Integer DEFAULT value can be anything.
If you want to add String type column, add in the following manner:
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'address' TEXT")
This works like a charm.
1
The only correct answer
– kulikovman
Mar 8 at 9:03
@kulikovman Thanks !!
– Prabhtej Singh
Mar 8 at 10:03
add a comment |
I faced this issue today, I just changed int
fields to Integer
in Entities
. As int
cannot be null but Integer
objects could be null.
add a comment |
If you are getting notNull differences, you can simply mark your class field with @NonNull annotation, or change your sql with ALTER TABLE. But if you are getting column type differences, such as expected: TYPE=TEXT, then found TYPE='' (COLLATE NOCASE), or expected INTEGER, found INT, then the only solution is to drop and recreate your table. Sqlite does not allow changing column types.
Use INTEGER in Sqlite instead of INT and mark your Java entity with @ColumnInfo(collate = NOCASE) (if you use NOCASE in Sqlite).
Take a look at the json file under appschemas to get the sql for the expected queries.
static final Migration MIGRATION_2_3= new Migration(2, 3) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("DROP TABLE IF EXISTS table_tmp");
database.execSQL("CREATE TABLE IF NOT EXISTS `table_tmp` ...");
database.execSQL("insert into table_tmp (`id`, `name` , ...");
database.execSQL("DROP INDEX IF EXISTS `index_table_name`");
database.execSQL("CREATE INDEX IF NOT EXISTS `index_table_name` ON `table_tmp` (`name`)");
database.execSQL("DROP TABLE IF EXISTS table");
database.execSQL("alter table table_tmp rename to table");
}
};
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f46372036%2froom-database-migration-doesnt-properly-handle-alter-table-migration%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
The error message is hard to parse, but there's a difference:
TableInfo{name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, age=Column{name='age', type='INTEGER', notNull=true, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}}, foreignKeys=} Found:
Found
TableInfo{ name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}, age=Column{name='age', type='INTEGER', notNull=false, primaryKeyPosition=0}}, foreignKeys=}
Age is nullable but Room expected it to be not null.
Change your migration to:
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL");
Since this exception explanation is VERY difficult to parse, I have created a small script that does the diff for you.
Example:
mig "java.lang.IllegalStateException: Migration failed. expected:TableInfo{name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, age=Column{name='age', type='INTEGER', notNull=true, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}}, foreignKeys=} , found:TableInfo{name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}, age=Column{name='age', type='INTEGER', notNull=false, primaryKeyPosition=0}}, foreignKeys=}"
Result:
1
Works like a charm, thanks for helping. And now I understand, when you perform migrations, you must specify the DEFAULT value for the new column to be populated.
– diogojme
Sep 25 '17 at 17:43
Try your migrations on a dummy database and see if the query does what you expect it to do.
– Benoit Duffez
Sep 25 '17 at 18:40
For sure I will, thanks for the feedback.
– diogojme
Sep 25 '17 at 20:36
This doesnt work for me although it should..
– Ali Kazi
May 21 '18 at 1:54
1
I also found something interesting: if you created indices in your @Entity annotation in your model, you need to also do it in SQL in your migration script, for exampleCREATE INDEX
index_History_nodeId` ONHistory
(nodeId
)` and if you don't you'll get aMigration didn't properly handle
– Raphael C
May 31 '18 at 14:02
|
show 2 more comments
The error message is hard to parse, but there's a difference:
TableInfo{name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, age=Column{name='age', type='INTEGER', notNull=true, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}}, foreignKeys=} Found:
Found
TableInfo{ name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}, age=Column{name='age', type='INTEGER', notNull=false, primaryKeyPosition=0}}, foreignKeys=}
Age is nullable but Room expected it to be not null.
Change your migration to:
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL");
Since this exception explanation is VERY difficult to parse, I have created a small script that does the diff for you.
Example:
mig "java.lang.IllegalStateException: Migration failed. expected:TableInfo{name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, age=Column{name='age', type='INTEGER', notNull=true, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}}, foreignKeys=} , found:TableInfo{name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}, age=Column{name='age', type='INTEGER', notNull=false, primaryKeyPosition=0}}, foreignKeys=}"
Result:
1
Works like a charm, thanks for helping. And now I understand, when you perform migrations, you must specify the DEFAULT value for the new column to be populated.
– diogojme
Sep 25 '17 at 17:43
Try your migrations on a dummy database and see if the query does what you expect it to do.
– Benoit Duffez
Sep 25 '17 at 18:40
For sure I will, thanks for the feedback.
– diogojme
Sep 25 '17 at 20:36
This doesnt work for me although it should..
– Ali Kazi
May 21 '18 at 1:54
1
I also found something interesting: if you created indices in your @Entity annotation in your model, you need to also do it in SQL in your migration script, for exampleCREATE INDEX
index_History_nodeId` ONHistory
(nodeId
)` and if you don't you'll get aMigration didn't properly handle
– Raphael C
May 31 '18 at 14:02
|
show 2 more comments
The error message is hard to parse, but there's a difference:
TableInfo{name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, age=Column{name='age', type='INTEGER', notNull=true, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}}, foreignKeys=} Found:
Found
TableInfo{ name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}, age=Column{name='age', type='INTEGER', notNull=false, primaryKeyPosition=0}}, foreignKeys=}
Age is nullable but Room expected it to be not null.
Change your migration to:
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL");
Since this exception explanation is VERY difficult to parse, I have created a small script that does the diff for you.
Example:
mig "java.lang.IllegalStateException: Migration failed. expected:TableInfo{name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, age=Column{name='age', type='INTEGER', notNull=true, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}}, foreignKeys=} , found:TableInfo{name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}, age=Column{name='age', type='INTEGER', notNull=false, primaryKeyPosition=0}}, foreignKeys=}"
Result:
The error message is hard to parse, but there's a difference:
TableInfo{name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, age=Column{name='age', type='INTEGER', notNull=true, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}}, foreignKeys=} Found:
Found
TableInfo{ name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}, age=Column{name='age', type='INTEGER', notNull=false, primaryKeyPosition=0}}, foreignKeys=}
Age is nullable but Room expected it to be not null.
Change your migration to:
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL");
Since this exception explanation is VERY difficult to parse, I have created a small script that does the diff for you.
Example:
mig "java.lang.IllegalStateException: Migration failed. expected:TableInfo{name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, age=Column{name='age', type='INTEGER', notNull=true, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}}, foreignKeys=} , found:TableInfo{name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}, age=Column{name='age', type='INTEGER', notNull=false, primaryKeyPosition=0}}, foreignKeys=}"
Result:
edited Mar 2 '18 at 13:24
answered Sep 23 '17 at 12:45
Benoit DuffezBenoit Duffez
5,854957102
5,854957102
1
Works like a charm, thanks for helping. And now I understand, when you perform migrations, you must specify the DEFAULT value for the new column to be populated.
– diogojme
Sep 25 '17 at 17:43
Try your migrations on a dummy database and see if the query does what you expect it to do.
– Benoit Duffez
Sep 25 '17 at 18:40
For sure I will, thanks for the feedback.
– diogojme
Sep 25 '17 at 20:36
This doesnt work for me although it should..
– Ali Kazi
May 21 '18 at 1:54
1
I also found something interesting: if you created indices in your @Entity annotation in your model, you need to also do it in SQL in your migration script, for exampleCREATE INDEX
index_History_nodeId` ONHistory
(nodeId
)` and if you don't you'll get aMigration didn't properly handle
– Raphael C
May 31 '18 at 14:02
|
show 2 more comments
1
Works like a charm, thanks for helping. And now I understand, when you perform migrations, you must specify the DEFAULT value for the new column to be populated.
– diogojme
Sep 25 '17 at 17:43
Try your migrations on a dummy database and see if the query does what you expect it to do.
– Benoit Duffez
Sep 25 '17 at 18:40
For sure I will, thanks for the feedback.
– diogojme
Sep 25 '17 at 20:36
This doesnt work for me although it should..
– Ali Kazi
May 21 '18 at 1:54
1
I also found something interesting: if you created indices in your @Entity annotation in your model, you need to also do it in SQL in your migration script, for exampleCREATE INDEX
index_History_nodeId` ONHistory
(nodeId
)` and if you don't you'll get aMigration didn't properly handle
– Raphael C
May 31 '18 at 14:02
1
1
Works like a charm, thanks for helping. And now I understand, when you perform migrations, you must specify the DEFAULT value for the new column to be populated.
– diogojme
Sep 25 '17 at 17:43
Works like a charm, thanks for helping. And now I understand, when you perform migrations, you must specify the DEFAULT value for the new column to be populated.
– diogojme
Sep 25 '17 at 17:43
Try your migrations on a dummy database and see if the query does what you expect it to do.
– Benoit Duffez
Sep 25 '17 at 18:40
Try your migrations on a dummy database and see if the query does what you expect it to do.
– Benoit Duffez
Sep 25 '17 at 18:40
For sure I will, thanks for the feedback.
– diogojme
Sep 25 '17 at 20:36
For sure I will, thanks for the feedback.
– diogojme
Sep 25 '17 at 20:36
This doesnt work for me although it should..
– Ali Kazi
May 21 '18 at 1:54
This doesnt work for me although it should..
– Ali Kazi
May 21 '18 at 1:54
1
1
I also found something interesting: if you created indices in your @Entity annotation in your model, you need to also do it in SQL in your migration script, for example
CREATE INDEX
index_History_nodeId` ON History
(nodeId
)` and if you don't you'll get a Migration didn't properly handle
– Raphael C
May 31 '18 at 14:02
I also found something interesting: if you created indices in your @Entity annotation in your model, you need to also do it in SQL in your migration script, for example
CREATE INDEX
index_History_nodeId` ON History
(nodeId
)` and if you don't you'll get a Migration didn't properly handle
– Raphael C
May 31 '18 at 14:02
|
show 2 more comments
I too wrote a small JS script which you can find https://hrankit.github.io/RoomSQLiteDifferenceFinder/
The process is pretty Simple.
Input the Expected error log in Expected column which is the Left One.
Input the Found error log in Found column which is the Right One.
Press Go. button. The error logs get converted to JSON.
Press Compare button and Voila, you have the difference you need.
This plugin finds out the difference in the two Expected and Found dump from the Android Studio Logcat.
Checkout the image of comparison here
2
Whilst this may theoretically answer the question, it would be preferable to include the essential parts of the answer here, and provide the link for reference.
– Adriaan
Sep 1 '18 at 11:53
@HRankit Just Awesome, your script solved my problem.
– Ritesh Adulkar
Jan 9 at 15:32
add a comment |
I too wrote a small JS script which you can find https://hrankit.github.io/RoomSQLiteDifferenceFinder/
The process is pretty Simple.
Input the Expected error log in Expected column which is the Left One.
Input the Found error log in Found column which is the Right One.
Press Go. button. The error logs get converted to JSON.
Press Compare button and Voila, you have the difference you need.
This plugin finds out the difference in the two Expected and Found dump from the Android Studio Logcat.
Checkout the image of comparison here
2
Whilst this may theoretically answer the question, it would be preferable to include the essential parts of the answer here, and provide the link for reference.
– Adriaan
Sep 1 '18 at 11:53
@HRankit Just Awesome, your script solved my problem.
– Ritesh Adulkar
Jan 9 at 15:32
add a comment |
I too wrote a small JS script which you can find https://hrankit.github.io/RoomSQLiteDifferenceFinder/
The process is pretty Simple.
Input the Expected error log in Expected column which is the Left One.
Input the Found error log in Found column which is the Right One.
Press Go. button. The error logs get converted to JSON.
Press Compare button and Voila, you have the difference you need.
This plugin finds out the difference in the two Expected and Found dump from the Android Studio Logcat.
Checkout the image of comparison here
I too wrote a small JS script which you can find https://hrankit.github.io/RoomSQLiteDifferenceFinder/
The process is pretty Simple.
Input the Expected error log in Expected column which is the Left One.
Input the Found error log in Found column which is the Right One.
Press Go. button. The error logs get converted to JSON.
Press Compare button and Voila, you have the difference you need.
This plugin finds out the difference in the two Expected and Found dump from the Android Studio Logcat.
Checkout the image of comparison here
edited Nov 2 '18 at 5:02
eyllanesc
84.5k103562
84.5k103562
answered Sep 1 '18 at 11:50
HRankitHRankit
7122
7122
2
Whilst this may theoretically answer the question, it would be preferable to include the essential parts of the answer here, and provide the link for reference.
– Adriaan
Sep 1 '18 at 11:53
@HRankit Just Awesome, your script solved my problem.
– Ritesh Adulkar
Jan 9 at 15:32
add a comment |
2
Whilst this may theoretically answer the question, it would be preferable to include the essential parts of the answer here, and provide the link for reference.
– Adriaan
Sep 1 '18 at 11:53
@HRankit Just Awesome, your script solved my problem.
– Ritesh Adulkar
Jan 9 at 15:32
2
2
Whilst this may theoretically answer the question, it would be preferable to include the essential parts of the answer here, and provide the link for reference.
– Adriaan
Sep 1 '18 at 11:53
Whilst this may theoretically answer the question, it would be preferable to include the essential parts of the answer here, and provide the link for reference.
– Adriaan
Sep 1 '18 at 11:53
@HRankit Just Awesome, your script solved my problem.
– Ritesh Adulkar
Jan 9 at 15:32
@HRankit Just Awesome, your script solved my problem.
– Ritesh Adulkar
Jan 9 at 15:32
add a comment |
None of the answers are correct in any of the links. After much experiments, found a way for it. The ALTER query needs to be written in the following way to make it work:
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL DEFAULT 0")
However, the Integer DEFAULT value can be anything.
If you want to add String type column, add in the following manner:
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'address' TEXT")
This works like a charm.
1
The only correct answer
– kulikovman
Mar 8 at 9:03
@kulikovman Thanks !!
– Prabhtej Singh
Mar 8 at 10:03
add a comment |
None of the answers are correct in any of the links. After much experiments, found a way for it. The ALTER query needs to be written in the following way to make it work:
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL DEFAULT 0")
However, the Integer DEFAULT value can be anything.
If you want to add String type column, add in the following manner:
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'address' TEXT")
This works like a charm.
1
The only correct answer
– kulikovman
Mar 8 at 9:03
@kulikovman Thanks !!
– Prabhtej Singh
Mar 8 at 10:03
add a comment |
None of the answers are correct in any of the links. After much experiments, found a way for it. The ALTER query needs to be written in the following way to make it work:
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL DEFAULT 0")
However, the Integer DEFAULT value can be anything.
If you want to add String type column, add in the following manner:
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'address' TEXT")
This works like a charm.
None of the answers are correct in any of the links. After much experiments, found a way for it. The ALTER query needs to be written in the following way to make it work:
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL DEFAULT 0")
However, the Integer DEFAULT value can be anything.
If you want to add String type column, add in the following manner:
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'address' TEXT")
This works like a charm.
edited Nov 16 '18 at 8:43
quant
1,60711527
1,60711527
answered Nov 16 '18 at 7:07
Prabhtej SinghPrabhtej Singh
585
585
1
The only correct answer
– kulikovman
Mar 8 at 9:03
@kulikovman Thanks !!
– Prabhtej Singh
Mar 8 at 10:03
add a comment |
1
The only correct answer
– kulikovman
Mar 8 at 9:03
@kulikovman Thanks !!
– Prabhtej Singh
Mar 8 at 10:03
1
1
The only correct answer
– kulikovman
Mar 8 at 9:03
The only correct answer
– kulikovman
Mar 8 at 9:03
@kulikovman Thanks !!
– Prabhtej Singh
Mar 8 at 10:03
@kulikovman Thanks !!
– Prabhtej Singh
Mar 8 at 10:03
add a comment |
I faced this issue today, I just changed int
fields to Integer
in Entities
. As int
cannot be null but Integer
objects could be null.
add a comment |
I faced this issue today, I just changed int
fields to Integer
in Entities
. As int
cannot be null but Integer
objects could be null.
add a comment |
I faced this issue today, I just changed int
fields to Integer
in Entities
. As int
cannot be null but Integer
objects could be null.
I faced this issue today, I just changed int
fields to Integer
in Entities
. As int
cannot be null but Integer
objects could be null.
answered Dec 14 '18 at 15:20
Zaid MirzaZaid Mirza
1,71211125
1,71211125
add a comment |
add a comment |
If you are getting notNull differences, you can simply mark your class field with @NonNull annotation, or change your sql with ALTER TABLE. But if you are getting column type differences, such as expected: TYPE=TEXT, then found TYPE='' (COLLATE NOCASE), or expected INTEGER, found INT, then the only solution is to drop and recreate your table. Sqlite does not allow changing column types.
Use INTEGER in Sqlite instead of INT and mark your Java entity with @ColumnInfo(collate = NOCASE) (if you use NOCASE in Sqlite).
Take a look at the json file under appschemas to get the sql for the expected queries.
static final Migration MIGRATION_2_3= new Migration(2, 3) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("DROP TABLE IF EXISTS table_tmp");
database.execSQL("CREATE TABLE IF NOT EXISTS `table_tmp` ...");
database.execSQL("insert into table_tmp (`id`, `name` , ...");
database.execSQL("DROP INDEX IF EXISTS `index_table_name`");
database.execSQL("CREATE INDEX IF NOT EXISTS `index_table_name` ON `table_tmp` (`name`)");
database.execSQL("DROP TABLE IF EXISTS table");
database.execSQL("alter table table_tmp rename to table");
}
};
add a comment |
If you are getting notNull differences, you can simply mark your class field with @NonNull annotation, or change your sql with ALTER TABLE. But if you are getting column type differences, such as expected: TYPE=TEXT, then found TYPE='' (COLLATE NOCASE), or expected INTEGER, found INT, then the only solution is to drop and recreate your table. Sqlite does not allow changing column types.
Use INTEGER in Sqlite instead of INT and mark your Java entity with @ColumnInfo(collate = NOCASE) (if you use NOCASE in Sqlite).
Take a look at the json file under appschemas to get the sql for the expected queries.
static final Migration MIGRATION_2_3= new Migration(2, 3) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("DROP TABLE IF EXISTS table_tmp");
database.execSQL("CREATE TABLE IF NOT EXISTS `table_tmp` ...");
database.execSQL("insert into table_tmp (`id`, `name` , ...");
database.execSQL("DROP INDEX IF EXISTS `index_table_name`");
database.execSQL("CREATE INDEX IF NOT EXISTS `index_table_name` ON `table_tmp` (`name`)");
database.execSQL("DROP TABLE IF EXISTS table");
database.execSQL("alter table table_tmp rename to table");
}
};
add a comment |
If you are getting notNull differences, you can simply mark your class field with @NonNull annotation, or change your sql with ALTER TABLE. But if you are getting column type differences, such as expected: TYPE=TEXT, then found TYPE='' (COLLATE NOCASE), or expected INTEGER, found INT, then the only solution is to drop and recreate your table. Sqlite does not allow changing column types.
Use INTEGER in Sqlite instead of INT and mark your Java entity with @ColumnInfo(collate = NOCASE) (if you use NOCASE in Sqlite).
Take a look at the json file under appschemas to get the sql for the expected queries.
static final Migration MIGRATION_2_3= new Migration(2, 3) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("DROP TABLE IF EXISTS table_tmp");
database.execSQL("CREATE TABLE IF NOT EXISTS `table_tmp` ...");
database.execSQL("insert into table_tmp (`id`, `name` , ...");
database.execSQL("DROP INDEX IF EXISTS `index_table_name`");
database.execSQL("CREATE INDEX IF NOT EXISTS `index_table_name` ON `table_tmp` (`name`)");
database.execSQL("DROP TABLE IF EXISTS table");
database.execSQL("alter table table_tmp rename to table");
}
};
If you are getting notNull differences, you can simply mark your class field with @NonNull annotation, or change your sql with ALTER TABLE. But if you are getting column type differences, such as expected: TYPE=TEXT, then found TYPE='' (COLLATE NOCASE), or expected INTEGER, found INT, then the only solution is to drop and recreate your table. Sqlite does not allow changing column types.
Use INTEGER in Sqlite instead of INT and mark your Java entity with @ColumnInfo(collate = NOCASE) (if you use NOCASE in Sqlite).
Take a look at the json file under appschemas to get the sql for the expected queries.
static final Migration MIGRATION_2_3= new Migration(2, 3) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("DROP TABLE IF EXISTS table_tmp");
database.execSQL("CREATE TABLE IF NOT EXISTS `table_tmp` ...");
database.execSQL("insert into table_tmp (`id`, `name` , ...");
database.execSQL("DROP INDEX IF EXISTS `index_table_name`");
database.execSQL("CREATE INDEX IF NOT EXISTS `index_table_name` ON `table_tmp` (`name`)");
database.execSQL("DROP TABLE IF EXISTS table");
database.execSQL("alter table table_tmp rename to table");
}
};
edited Feb 19 at 14:49
answered Nov 2 '18 at 4:16
live-lovelive-love
17.9k108987
17.9k108987
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f46372036%2froom-database-migration-doesnt-properly-handle-alter-table-migration%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
A bit of a shot in the dark, but perhaps try
"ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL DEFAULT 0"
(0 could be whatever you consider suitable).– MikeT
Sep 22 '17 at 22:33
1
Room expects the column order to match the field order. It would appear that the results of the
ALTER TABLE
are resulting in a different order.– CommonsWare
Sep 23 '17 at 11:36
Check bellow answer. It has complete description: stackoverflow.com/a/51245898/3073945
– Md. Sajedul Karim
Jul 9 '18 at 12:49