Я считаю, что проблема не в добавлении нового столбца, а в том, что значение по умолчанию применено / изменено / удалено к существующему столбцу. Тогда вам, возможно, придется воссоздать соответствующие таблицы.
, например, если вы изменили: -
@ColumnInfo(name = "dummy0")
@NonNull
public String dummy0;
, чтобы добавить значение по умолчанию
@ColumnInfo(name = "dummy0", defaultValue = "")
@NonNull
public String dummy0;
Тогда будет несоответствие схемы, потому что ожидаемая схема будет иметь DEFAULT ''
, в то время как найденная схема (исходная база данных) не имеет кодировки по умолчанию.
- Это потребует, чтобы таблица была удалена и воссоздана как Вы не можете изменить параметры атрибута столбца ALTER.
Если до 2.2.0 у вас была предыдущая не сгенерированная некоммерческая схема, которая включала значения по умолчанию и объекты не были изменены соответствующим образом, то вы бы сделали это. получите cla sh, потому что ожидаемая схема не имеет значения по умолчанию, в то время как найденная схема содержит DEFAULT = ''
.
- Это потребует соответствующего изменения сущностей.
Пример
Предполагается, что текущий объект: -
@Entity(tableName = "password")
public class Password {
@PrimaryKey
public Long id;
@ColumnInfo(name = "dummy0")
@NonNull
public String dummy0;
@ColumnInfo(name = "dummy1")
@NonNull
public String dummy1;
}
Тогда сгенерированный код для создания таблицы: -
_db.execSQL("CREATE TABLE IF NOT EXISTS `password` (`id` INTEGER, `dummy0` TEXT NOT NULL, `dummy1` TEXT NOT NULL, PRIMARY KEY(`id`))");
- Приложение было запустить с вышеупомянутым, чтобы создать e база данных.
Если теперь для Версии 2 она изменена на: -
@Entity(tableName = "password")
public class Password {
@PrimaryKey
public Long id;
@ColumnInfo(name = "dummy0", defaultValue = "" /*<<<<<<<<<< ADDED */)
@NonNull
public String dummy0;
@ColumnInfo(name = "dummy1")
@NonNull
public String dummy1;
}
Тогда сгенерированный код: -
_db.execSQL("CREATE TABLE IF NOT EXISTS `password` (`id` INTEGER, `dummy0` TEXT NOT NULL DEFAULT '', `dummy1` TEXT NOT NULL, PRIMARY KEY(`id`))");
Выполняется с немой / пустой миграцией (1-2), затем: -
- Найденная схема (исходная БД) имеет: -
defaultValue='null'
- Но ожидаемая схема имеет: -
defaultValue=''''
Согласно: -
2020-01-11 19:11:15.300 12539-12539/a.so59691979 E/AndroidRuntime: FATAL EXCEPTION: main
Process: a.so59691979, PID: 12539
java.lang.RuntimeException: Unable to start activity ComponentInfo{a.so59691979/a.so59691979.MainActivity}: java.lang.IllegalStateException: Migration didn't properly handle: password(a.so59691979.Password).
Expected:
TableInfo{name='password', columns={dummy0=Column{name='dummy0', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue=''''}, dummy1=Column{name='dummy1', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, id=Column{name='id', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'}}, foreignKeys=[], indices=[]}
Found:
TableInfo{name='password', columns={dummy0=Column{name='dummy0', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, dummy1=Column{name='dummy1', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, id=Column{name='id', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'}}, foreignKeys=[], indices=[]}
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)
Пример исправления
Использование миграции: -
Migration M1_2 = new Migration(1,2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
// CREATE SQL Copied from the generated Java PasswordDatabase_Impl (name changed)
final String SQL_CREATE_NEW_PASSWORDTABLE =
"CREATE TABLE IF NOT EXISTS `password_new` (`id` INTEGER, `dummy0` TEXT NOT NULL DEFAULT '', `dummy1` TEXT NOT NULL, PRIMARY KEY(`id`))";
database.execSQL(SQL_CREATE_NEW_PASSWORDTABLE);
database.execSQL("INSERT INTO `password_new` SELECT * FROM `password`");
database.execSQL("ALTER TABLE `password` RENAME TO `password_old`");
database.execSQL("ALTER TABLE `password_new` RENAME TO `password`");
database.execSQL("DROP TABLE IF EXISTS `password_old`");
}
}
Устраняет проблему .
Код
Для создания вышеуказанного кода использовался следующий код: -
Пароль. java
/*
//Original
@Entity(tableName = "password")
public class Password {
@PrimaryKey
public Long id;
@ColumnInfo(name = "dummy0")
@NonNull
public String dummy0;
@ColumnInfo(name = "dummy1")
@NonNull
public String dummy1;
}
*/
// New
@Entity(tableName = "password")
public class Password {
@PrimaryKey
public Long id;
@ColumnInfo(name = "dummy0", defaultValue = "" /*<<<<<<<<<< ADDED */)
@NonNull
public String dummy0;
@ColumnInfo(name = "dummy1")
@NonNull
public String dummy1;
}
- Первоначально использовался оригинал
PasswordDatabase. java
@Database(version = 2, entities = {Password.class})
public abstract class PasswordDatabase extends RoomDatabase {
}
MainActivity. java
publi c Класс MainActivity расширяет AppCompatActivity {
PasswordDatabase passwordDatabase;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
passwordDatabase = Room.databaseBuilder(
this,
PasswordDatabase.class,
"passworddb"
)
.allowMainThreadQueries()
.addMigrations(M1_2)
.build();
passwordDatabase.getOpenHelper().getWritableDatabase();
}
Migration M1_2 = new Migration(1,2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
// CREATE SQL Copied from the generated Java PasswordDatabase_Impl (name changed)
final String SQL_CREATE_NEW_PASSWORDTABLE =
"CREATE TABLE IF NOT EXISTS `password_new` (`id` INTEGER, `dummy0` TEXT NOT NULL DEFAULT '', `dummy1` TEXT NOT NULL, PRIMARY KEY(`id`))";
database.execSQL(SQL_CREATE_NEW_PASSWORDTABLE);
database.execSQL("INSERT INTO `password_new` SELECT * FROM `password`");
database.execSQL("ALTER TABLE `password` RENAME TO `password_old`");
database.execSQL("ALTER TABLE `password_new` RENAME TO `password`");
database.execSQL("DROP TABLE IF EXISTS `password_old`");
}
};
- Изначально тело M1_2 было пустым (поэтому как заставить ошибку)