Java.lang.IllegalStateException
移行はユーザー(therealandroid.github.com.roomcore.Java.User)を適切に処理しませんでした。
期待される:
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 = []}が見つかりました:
見つかった
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 = []}
単純な移行を実行しようとしています。User
というクラスがあり、2つの列ID (primary key)
とNAME TEXT
があり、データベースに2人のユーザーデータを入力してから、列AGE
をオブジェクトUser
に追加し、移行定数にalter table
を追加してこの新しい列を追加し、最後にデータベースのバージョンを1から2に置き換えます。
ここにコードがあります
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(entities = {User.class}, version = 2)
public abstract class RoomDatabaseImpl extends RoomDatabase {
abstract UserDao userDao();
}
移行コード
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");
}
};
そしてそれは呼び出す
Room.databaseBuilder(context, RoomDatabaseImpl.class, "Sample.db")
.addMigrations(MIGRATION_1_2)
.allowMainThreadQueries()
.build();
AGE
を追加して移行を実行するオブジェクトを変更する前に、2つのレジスタを追加すると動作します。
移行を実行した後、次のように新しいユーザーを追加しようとしました。
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
その他の情報:
Android Studio 3と私は実際にテストしませんでした。
依存関係:
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
誰かが私を助けてくれますか、私は本当に私が間違っているのか、それがバグであるのか分かりません。
エラーメッセージの解析は困難ですが、違いがあります。
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 = []}が見つかりました:
見つかった
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 = []}
年齢はnull可能ですが、Roomはnullでないと予測しました。
移行を次のように変更します。
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL");
この例外の説明は解析が非常に難しいため、差分を作成する 小さなスクリプト を作成しました。
例:
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=[]}"
結果:
私もあなたが見つけることができる小さなJSスクリプトを書きました https://hrankit.github.io/RoomSQLiteDifferenceFinder/
プロセスは非常に簡単です。
左の「期待される」列に期待されるエラーログを入力します。
見つかったエラーログを、正しい列である[検出]列に入力します。
Goを押します。ボタン。エラーログはJSONに変換されます。
比較ボタンと出来上がりを押すと、必要な違いがあります。
このプラグインは、Android Studio Logcat。
比較の画像はこちらからご覧ください
どのリンクでも正しい答えはありません。多くの実験の後、その方法を見つけました。 ALTERクエリを機能させるには、次の方法で記述する必要があります。
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL DEFAULT 0")
ただし、整数のデフォルト値は何でもかまいません。
文字列型の列を追加する場合は、次の方法で追加します。
database.execSQL("ALTER TABLE 'user' ADD COLUMN 'address' TEXT")
これは魅力のように機能します。
今日、この問題に直面しました。int
のInteger
フィールドをEntities
に変更しました。 int
をnullにすることはできませんが、Integer
オブジェクトはnullにすることができます。
NotNullの違いが生じている場合は、クラスフィールドに@NonNullアノテーションを付けるか、ALTER TABLEでSQLを変更するだけです。しかし、期待される列タイプの違いを取得している場合:TYPE = TEXT、見つかったTYPE = ''(COLLATE NOCASE)、または予想されたINTEGER、見つかったINT、唯一の解決策はテーブルを削除して再作成することです。 Sqliteでは、列の種類を変更できません。
INTの代わりにSqliteでINTEGERを使用して、Javaエンティティを@ColumnInfo(collate = NOCASE)でマークします(SqliteでNOCASEを使用する場合))。
App\schemasの下のjsonファイルを見て、予想されるクエリのsqlを取得します。
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");
}
};