Невозможно перенести таблицу в Room do из-за ошибки сохранения логических значений в Sqlite.

Я пытался перенести мое приложение в Room . Я борюсь с конкретной таблицей, которую нельзя перенести напрямую из-за способа ее создания.

Поля были созданы с типом данных BOOL и BYTE вместо INTEGER .

Я уже не смог попробовать:

  • Измените мои поля сущности на Int / Boolean / Byte с той же ошибкой
  • Создание TypeConverter, чтобы сохранить его как Boolean / Byte
  • Добавление typeAffinity как typeAffinity в @ColumnInfo моей сущности, которая является affinity = 1

Мое предложение по созданию databaseSQL :

CREATE TABLE IF NOT EXISTS myTable (_id INTEGER PRIMARY KEY AUTOINCREMENT,
my_first_field BOOL NOT NULL DEFAULT 0,
my_second_field BYTE NOT NULL DEFAULT 0)

Моя сущность:

@Entity(tableName = "myTable")
data class MyTable(
        @PrimaryKey(autoGenerate = true)
        @ColumnInfo(name = "_id")
        var id: Int,

        @ColumnInfo(name = "my_first_field")
        var myFirstField: Boolean = false,

        @ColumnInfo(name = "my_second_field")
        var mySecondField: Byte = false
)

Ошибка, которую я постоянно получаю:

Expected:
TableInfo{name='my_table', columns={_id=Column{name='_id', type='INTEGER', affinity=Ɖ', notNull=true, primaryKeyPosition=1}, my_first_field=Column{name='my_first_field', type='INTEGER', affinity=Ɖ', notNull=true, primaryKeyPosition=0}, my_second_field=Column{name='my_second_field', type='INTEGER', affinity=Ɖ', notNull=true, primaryKeyPosition=0}}, foreignKeys=[], indices=[]}
     Found:
TableInfo{name='my_table', columns={_id=Column{name='_id', type='INTEGER', affinity=Ɖ', notNull=true, primaryKeyPosition=1}, my_first_field=Column{name='my_first_field', type='BOOL', affinity=Ƈ', notNull=true, primaryKeyPosition=0}, my_second_field=Column{name='my_second_field', type='BYTE', affinity=Ƈ', notNull=true, primaryKeyPosition=0}}, foreignKeys=[], indices=[]}

Есть ли способ сделать прямо вперед, не создавая миграционную стратегию?

Всего 1 ответ


Я полагаю, что вы могли бы, прежде чем строить базу данных комнаты:

  1. Проверьте, нужно ли что-либо сделать, например, используя: -

    • SELECT count() FROM sqlite_master WHERE name = 'myTable' AND instr(sql,' BOOL ') AND instr(sql,' BYTE ');

    • а затем проверка результата.

    • Если оно равно 0, больше ничего не делайте (хотя для безопасности вы можете использовать DROP TABLE ЕСЛИ EXISTS oldmyTable, когда оно равно 0).

    • ТОЛЬКО если вышеуказанное возвращает 1, то:

  2. удалите переименованную исходную таблицу (см. ниже и выше) на случай, если она существует: -

    • DROP TABLE IF EXISTS oldmyTable;
  3. определить другую таблицу, используя

    • CREATE TABLE IF NOT EXISTS myOtherTable (_id INTEGER PRIMARY KEY AUTOINCREMENT, my_first_field INTEGER NOT NULL DEFAULT 0, my_second_field INTEGER NOT NULL DEFAULT 0)

    • т.е. ожидаемая схема

  4. заполнить новую таблицу, используя

    • INSERT INTO myOtherTable SELECT * FROM myTable;
  5. переименуйте mytable, используя: -

    • ALTER TABLE mytable RENAME TO oldmyTable;
  6. переименуйте myOtherTable, используя оригинальное имя: -

    • ALTER TABLE myOtherTable RENAME TO mytable;
  7. отбросьте переименованную исходную таблицу (очевидно, только при тестировании): -

    • DROP TABLE IF EXISTS oldmyTable;

      • Вы можете пропустить это, пока не убедитесь, что миграция сработала.

Чистый результат состоит в том, что таблица должна быть такой, как ожидается .


Что касается комментария: -

Проблема в том, что мне нужно перенести 16-20 таблиц.

Вы можете использовать что-то вроде: -

public static int preMigrateAdjustment(SQLiteDatabase mDB) {

    String original_rename_prefix = "old";
    String tempname_suffix = "temp";
    String newsql_column = "newsql";
    String[] columns = new String[]{
            "name",
            "replace(replace(sql,' BOOL ',' INTEGER '),' BYTE ',' INTEGER ') AS " + newsql_column
    };

    int count_done = 0;
    String whereclause = "name LIKE('" + 
            original_rename_prefix +
            "%') AND type = 'table'";
    Cursor csr = mDB.query("sqlite_master",null,whereclause,null,null,null,null);
    while (csr.moveToNext()) {
        mDB.execSQL("DROP TABLE IF EXISTS " + csr.getString(csr.getColumnIndex("name")));
    }


    whereclause = "type = 'table' AND (instr(sql,' BOOL ')  OR instr(sql,' BYTE '))";
    csr = mDB.query(
            "sqlite_master",
            columns,
            whereclause,
            null,null,null,null
    );
    while (csr.moveToNext()) {
        String base_table_name = csr.getString(csr.getColumnIndex("name"));
        String newsql = csr.getString(csr.getColumnIndex(newsql_column));
        String temp_table_name = base_table_name + tempname_suffix;
        String renamed_table_name = original_rename_prefix+base_table_name;
        mDB.execSQL(newsql.replace(base_table_name,temp_table_name));
        mDB.execSQL("INSERT INTO " + temp_table_name + " SELECT * FROM " + base_table_name);
        mDB.execSQL("ALTER TABLE " + base_table_name + " RENAME TO " + renamed_table_name);
        mDB.execSQL("ALTER TABLE " + temp_table_name + " RENAME TO " + base_table_name);
        count_done++;
    }
    whereclause = "name LIKE('" + 
            original_rename_prefix +
            "%') AND type = 'table'";
    csr = mDB.query("sqlite_master",null,whereclause,null,null,null,null);
    while (csr.moveToNext()) {
        mDB.execSQL("DROP TABLE IF EXISTS " + csr.getString(csr.getColumnIndex("name")));
    }
    csr.close();
    return count_done;
}
  • Обратите внимание, что это не является доказательством, например, если у вас есть таблицы, которые уже начинаются со старых, то они будут отброшены.
  • Вышесказанное предполагает второй запуск, чтобы фактически удалить переименованные исходные таблицы.

Есть идеи?

10000