Очистить таблицу и сбросить первичный ключ автоинкремента - PullRequest
1 голос
/ 03 октября 2019

Я хочу удалить все из моей таблицы и сбросить первичный ключ автоинкремента. Я делаю это:

@Query("delete from sqlite_sequence where name='bin';")
void delete();


@Query("DELETE FROM bin")
void nukeTable();

@Query("UPDATE SQLITE_SEQUENCE SET seq = 1 WHERE name = 'bin';")
void resetPrimaryKey();

Но это не работает

Ответы [ 2 ]

2 голосов
/ 03 октября 2019

Ваша проблема в том, что ROOM защищает от использования таблиц SQLite, т. Е. Тех, которые начинаются с sqlite_, поэтому вы не можете напрямую сбросить sqlite_sequence в ROOM.

Ниже приведены два способа обойти это и реализовать цель. сброса последовательности, в комнате. Третий вариант, который не показан, заключается в закрытии базы данных ROOM и последующем доступе к базе данных с использованием экземпляра SQLiteDatabase для сброса последовательности.

Параметр A

Это можно сделать с помощью УБРАТЬ таблицу и затем воссоздать ее, используя экземпляр SupportSQLiteDatabase.

Ниже приведена демонстрация варианта A (но также включает в себя ненужное закрытие базы данных Room, а также использование базы данных вне помещения для объекта, однако это было добавлено в качестве доказательства метода путем извлечения данныхfrom sqlite_sequence).

NOTE

Приведенный выше код является просто демонстрацией техники, и существуют проблемы с переключением вышеуказанного кода между комнатой и комнатой, которая не требуется длярешение.

Код тестирования ядра: -

    //Stage 1 load some data
    getRoomDB();
    mRowIdTestDao = mRTDB.rowIdTestDao();
    mRowIdTestDao.insertManyRowIdTests(
            new RowIdTest("A"),
            new RowIdTest("B"),
            new RowIdTest("C")
    );

    // Stage 2 close to room and dump sqlite_sequence
    //mRTDB.close();
    getNonRoomDB();
    DatabaseUtils.dumpCursor(mNotRoomdb.query("sqlite_sequence",null,null,null,null,null,null));
    mNotRoomdb.close();

    //Stage 3 clear sqlite_sequence by dropping the table using SupportSQLiteDatabase
    getRoomDB();
    mSuppDB.execSQL("DROP TABLE RowIdTest"); //<<<<<<<<<< DROP THE TABLE
    mSuppDB.execSQL("CREATE TABLE IF NOT EXISTS RowIdTest (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT)"); //<<<<<<<<<< CREATE THE TABLE

    // Stage 4 close to room and dump sqlite_sequence
    mRTDB.close();
    getNonRoomDB();
    DatabaseUtils.dumpCursor(mNotRoomdb.query("sqlite_sequence",null,null,null,null,null,null));
    mNotRoomdb.close();

    // Stage 5 check that all is OK again (add some rows)
    getRoomDB();
    mRowIdTestDao.insertManyRowIdTests(
            new RowIdTest("A"),
            new RowIdTest("B"),
            new RowIdTest("C")
    );

    DatabaseUtils.dumpCursor(mSuppDB.query("SELECT * FROM RowIdTest"));

Вызванные методы: -

RoomDatabase.Callback getSuppDb = new RoomDatabase.Callback() {

    @Override
    public void onOpen(@NonNull SupportSQLiteDatabase db) {
        super.onOpen(db);
        mSuppDB = db;
    }
};

private void getRoomDB() {
    mRTDB = Room.databaseBuilder(this,RoomTestingDatabase.class,"rtdb.db")
            .allowMainThreadQueries()
            .addCallback(getSuppDb)
            .build();
}

private void getNonRoomDB() {
    mNotRoomdb = SQLiteDatabase.openDatabase(
            this.getDatabasePath("rtdb.db").getPath(),
            null,
            SQLiteDatabase.OPEN_READWRITE
    );
}

Результат из журнала

2019-10-03 17:13:25.506 W/SQLiteConnection: Could not change the database journal mode of '/data/user/0/art.roomtesting/databases/rtdb.db' from 'wal' to 'TRUNCATE' because the database is locked.  This usually means that there are other open connections to the database which prevents the database from enabling or disabling write-ahead logging mode.  Proceeding without changing the journal mode.
2019-10-03 17:13:25.508 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@add2875
2019-10-03 17:13:25.508 I/System.out: 0 {
2019-10-03 17:13:25.508 I/System.out:    name=RowIdTest
2019-10-03 17:13:25.508 I/System.out:    seq=6
2019-10-03 17:13:25.508 I/System.out: }
2019-10-03 17:13:25.509 I/System.out: <<<<<
2019-10-03 17:13:25.511 E/SQLiteLog: (5) statement aborts at 1: [PRAGMA journal_mode=TRUNCATE] database is locked
2019-10-03 17:13:25.511 W/SQLiteConnection: Could not change the database journal mode of '/data/user/0/art.roomtesting/databases/rtdb.db' from 'wal' to 'TRUNCATE' because the database is locked.  This usually means that there are other open connections to the database which prevents the database from enabling or disabling write-ahead logging mode.  Proceeding without changing the journal mode.
2019-10-03 17:13:25.512 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@38ae98
2019-10-03 17:13:25.513 I/System.out: <<<<<
2019-10-03 17:13:25.518 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@f873957
2019-10-03 17:13:25.518 I/System.out: 0 {
2019-10-03 17:13:25.518 I/System.out:    id=1
2019-10-03 17:13:25.518 I/System.out:    name=A
2019-10-03 17:13:25.518 I/System.out: }
2019-10-03 17:13:25.518 I/System.out: 1 {
2019-10-03 17:13:25.518 I/System.out:    id=2
2019-10-03 17:13:25.518 I/System.out:    name=B
2019-10-03 17:13:25.518 I/System.out: }
2019-10-03 17:13:25.518 I/System.out: 2 {
2019-10-03 17:13:25.518 I/System.out:    id=3
2019-10-03 17:13:25.519 I/System.out:    name=C
2019-10-03 17:13:25.519 I/System.out: }
2019-10-03 17:13:25.519 I/System.out: <<<<<

Вариант B

Другой альтернативой является создание таблицы с AUTOINCREMENT, и, таким образом, идентификатор строки генерируется исключительно на основе строк в таблице. Я полагаю, что существует некоторая путаница в отношении отказа от использования AUTOINCREMENT (или) способ заключается в НЕ код autoGenerate = true И использовании Long не long (или Integer не int для типа, не рекомендуется).

Рассмотрим таблицу / сущность RowTestId, использованную выше, это: -

@Entity
public class RowIdTest {

    @PrimaryKey(autoGenerate = true)
    private long id;
    private String name;


    public RowIdTest() {};

    @Ignore
    public RowIdTest(String name){
        this.name = name;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Эквивалентная версия без AUTOINCREMENT будет: -

@Entity
public class AltRowIdTest {

    @PrimaryKey
    private Long id; //<<<<<<<<<< Long not long
    private String name;


    public AltRowIdTest() {};

    @Ignore
    public AltRowIdTest(String name){
        this.name = name;
    }

    public Long getId() { //<<<<<<<<<< Long not long
        return id;
    }

    public void setId(Long id) { //<<<<<<<<<< Long not long
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Также рассмотрим: -

    @Query("DELETE FROM AltRowIdTest")
    int clearAllAltRowIdTestRows();

А затем следующий код: -

    //Option B
    mAltRowIdTestDao.insertManyRowIdTests(new AltRowIdTest("X"),new AltRowIdTest("Y"),new AltRowIdTest("Z"));
    DatabaseUtils.dumpCursor(mSuppDB.query("SELECT * FROM AltRowIdTest"));
    mAltRowIdTestDao.clearAllAltRowIdTestRows();
    mAltRowIdTestDao.insertManyRowIdTests(new AltRowIdTest("X"),new AltRowIdTest("Y"),new AltRowIdTest("Z"));
    DatabaseUtils.dumpCursor(mSuppDB.query("SELECT * FROM AltRowIdTest"));

Результат в журнале: -

2019-10-03 17:49:31.783 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@561c44
2019-10-03 17:49:31.785 I/System.out: 0 {
2019-10-03 17:49:31.785 I/System.out:    id=1
2019-10-03 17:49:31.785 I/System.out:    name=A
2019-10-03 17:49:31.785 I/System.out: }
2019-10-03 17:49:31.785 I/System.out: 1 {
2019-10-03 17:49:31.785 I/System.out:    id=2
2019-10-03 17:49:31.785 I/System.out:    name=B
2019-10-03 17:49:31.785 I/System.out: }
2019-10-03 17:49:31.785 I/System.out: 2 {
2019-10-03 17:49:31.785 I/System.out:    id=3
2019-10-03 17:49:31.785 I/System.out:    name=C
2019-10-03 17:49:31.786 I/System.out: }
2019-10-03 17:49:31.786 I/System.out: <<<<<


2019-10-03 17:49:31.793 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@f369662
2019-10-03 17:49:31.794 I/System.out: 0 {
2019-10-03 17:49:31.794 I/System.out:    id=1
2019-10-03 17:49:31.794 I/System.out:    name=X
2019-10-03 17:49:31.794 I/System.out: }
2019-10-03 17:49:31.794 I/System.out: 1 {
2019-10-03 17:49:31.794 I/System.out:    id=2
2019-10-03 17:49:31.794 I/System.out:    name=Y
2019-10-03 17:49:31.794 I/System.out: }
2019-10-03 17:49:31.794 I/System.out: 2 {
2019-10-03 17:49:31.794 I/System.out:    id=3
2019-10-03 17:49:31.794 I/System.out:    name=Z
2019-10-03 17:49:31.794 I/System.out: }
2019-10-03 17:49:31.795 I/System.out: <<<<<

т.е. столбец id перезапускается с 1 после удаления всех строк или отличается от варианта A, если строки в конце удаляются, он будет повторно использовать освобожденные идентификаторы (бот не будет, если конечная строка не удалена). Кроме того, в отличие от AUTOINCREMENT, если достигается наибольшее значение идентификатора (9223372036854775807) (идентификатор причины всегда должен быть длинным или длинным, а не целым или целым) исключение SQLITE_FULL может не возникать, поскольку SQLite будет пытаться использовать случайное неиспользуемое случайное значениечисло (вы также можете почти удвоить доступный диапазон, используя отрицательные значения) .

0 голосов
/ 03 октября 2019

Ну, вы можете сделать это с двумя запросами:

delete from your_table;    

и

UPDATE SQLIT_SEQUENCE SET seq = 0 WHERE name='bin'

Это сделает свое дело. Идентификатор перезапустится.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...