SQLite
 sql >> Baza danych >  >> RDS >> SQLite

Android Room - Jak zresetować automatycznie wygenerowany klucz podstawowy tabeli przy każdym uruchomieniu aplikacji?

W celu wyczyszczenia tabel przy wyjściu, ale nie resetuje to indeksu uruchamiania klawiszy, zamiast tego rozpoczyna się w miejscu, w którym zostało przerwane podczas ostatniego uruchomienia.

....

"delete from sqlite_sequence gdzie name='Sequence Action'" Brak błędu, ale indeks również nie jest resetowany.

Musisz oba usunąć wszystkie wiersze w SequenceAction tabeli ORAZ usuń odpowiedni wiersz z sqlite_sequence.

To znaczy, gdy używane jest słowo kluczowe AUTOINCREMENT, używany jest inny algorytm. Jest to zgodne z następującymi zasadami:-

Znajdź najwyższą wartość z:a) przechowywania wartości tabeli w numerze sqlite_sequence i b) najwyższej wartości wiersza

Alternatywą byłoby nieużywanie AUTOINCREMENT słowo kluczowe, zamiast po prostu mieć ?? INTEGER PRIMARY KEY (gdzie ?? reprezentuje nazwę kolumny).

Nadal miałbyś unikalny identyfikator, który jest aliasem rowid kolumna, ale nie ma gwarancji, że zawsze będzie rosła. AUTOINCREMENT gwarantuje rosnący unikalny identyfikator, ale nie gwarantuje monotonicznie rosnącego unikalnego identyfikatora.

Przy każdym uruchomieniu aplikacji potrzebuję tego klucza, aby zaczynał się od 0.

Jednak SQLite ustawi pierwszą wartość na 1, a nie 0.

Poniższe działania działają i jak widać z AUTOINCREMENT (choć trochę hack) :-

DROP TABLE IF EXISTS SequenceAction;
DROP TRIGGER IF EXISTS use_zero_as_first_sequence;
CREATE TABLE IF NOT EXISTS SequenceAction (id INTEGER PRIMARY KEY AUTOINCREMENT, otherdata TEXT);
CREATE TRIGGER IF NOT EXISTS use_zero_as_first_sequence AFTER INSERT ON SequenceAction
    BEGIN 
        UPDATE SequenceAction SET id = id - 1 WHERE id = new.id;
    END
;
INSERT INTO SequenceAction VALUES(null,'TEST1'),(null,'TEST2'),(null,'TEST3');
SELECT * FROM SequenceAction;
-- RESET and RESTART FROM 0
DELETE FROM SequenceAction;
DELETE FROM sqlite_sequence WHERE name = 'SequenceAction';
INSERT INTO SequenceAction VALUES(null,'TEST4'),(null,'TEST5'),(null,'TEST6');
SELECT * FROM SequenceAction
  • Dwa instrukcje DROP wymagane tylko do testowania w celu usunięcia i przedefiniowania.

Powoduje to:-

Pierwsze zapytanie zwracające :-

i drugi powrót :-

Więc w istocie chcesz :-

DELETE FROM SequenceAction;
DELETE FROM sqlite_sequence WHERE name = 'SequenceAction';

A także wyzwalacz, jeśli chcesz, aby numeracja zaczynała się od 0, a nie od 1.

Alternatywnie, jeśli zrezygnowałeś z AUTOINCREMENT, możesz użyć nieco zmienionego wyzwalacza :-

CREATE TRIGGER IF NOT EXISTS use_zero_as_first_sequence 
    AFTER INSERT ON SequenceAction 
    WHEN (SELECT count() FROM SequenceAction) = 1
    BEGIN 
        UPDATE SequenceAction SET id = 0;
    END
;
  • To po prostu zmienia numerację pierwszego wstawionego wiersza (algorytm następnie dodaje 1 z kolejnych wstawianych)

A następnie po prostu usuń wszystkie wiersze tylko z tabeli SequenceAction, aby zresetować numerację.

Przykład użycia pokoju :-

Na podstawie Twojego kodu i powyższego przykładu, poniższa metoda wydaje się działać :-

private void resetSequenceAction() {
    SQLiteDatabase dbx;
    String sqlite_sequence_table = "sqlite_sequence";
    long initial_sacount;
    long post_sacount;
    long initial_ssn =0;
    long post_ssn = 0;
    Cursor csr;

    /*
        Need to Create Database and table if it doesn't exist
     */
    File f = this.getDatabasePath(TestDatabase.DBNAME);
    if (!f.exists()) {
        File d = new File(this.getDatabasePath(TestDatabase.DBNAME).getParent());
        d.mkdirs();
        dbx = SQLiteDatabase.openOrCreateDatabase(f,null);
        String crtsql = "CREATE TABLE IF NOT EXISTS " + SequenceAction.tablename + "(" +
                SequenceAction.id_column + " INTEGER PRIMARY KEY AUTOINCREMENT," +
                SequenceAction.actionType_column + " TEXT," +
                SequenceAction.extraInfo_column + " TEXT" +
                ")";
        dbx.execSQL(crtsql);
        /*
           Might as well create the Trigger as well
         */
        String triggerSql = "CREATE TRIGGER IF NOT EXISTS user_zero_as_first_rowid AFTER INSERT ON " +
                SequenceAction.tablename +
                " BEGIN " +
                " UPDATE " + SequenceAction.tablename +
                " SET " +
                SequenceAction.id_column + " = " + SequenceAction.id_column + " - 1 " +
                " WHERE " + SequenceAction.id_column + " = new." + SequenceAction.id_column + ";" +
                " END ";
        dbx.execSQL(triggerSql);

    } else {
        dbx = SQLiteDatabase.openDatabase(this.getDatabasePath(TestDatabase.DBNAME).getPath(),null, Context.MODE_PRIVATE);
    }

    /*
        Add trigger to set id's to 1 less than they were set to
     */
    initial_sacount = DatabaseUtils.queryNumEntries(dbx,SequenceAction.tablename);
    /*
        Delete all the rows at startup
     */
    String deleteAllSequenceIdRowsSql = "DELETE FROM " + SequenceAction.tablename;
    dbx.execSQL(deleteAllSequenceIdRowsSql);
    post_sacount = DatabaseUtils.queryNumEntries(dbx,SequenceAction.tablename);
    /*
        delete the sequence row from the sqlite_sequence table
     */
    csr = dbx.query(sqlite_sequence_table,
            new String[]{"seq"},"name=?",
            new String[]{SequenceAction.tablename},
            null,null,null
    );
    if (csr.moveToFirst()) {
        initial_ssn = csr.getLong(csr.getColumnIndex("seq"));
    }
    String deleteSqlLiteSequenceRow = "DELETE FROM " +
            sqlite_sequence_table +
            " WHERE name = '" + SequenceAction.tablename + "'";
    dbx.execSQL(deleteSqlLiteSequenceRow);
    csr = dbx.query(
            sqlite_sequence_table,
            new String[]{"seq"},
            "name=?",
            new String[]{SequenceAction.tablename},
            null,null,null
    );
    if (csr.moveToFirst()) {
        post_ssn = csr.getLong(csr.getColumnIndex("seq"));
    }
    csr.close();
    Log.d("SEQACTSTATS",
            "Initial Rowcount=" + String.valueOf(initial_sacount) +
                    " Initial Seq#=" + String.valueOf(initial_ssn) +
                    " Post Delete Rowcount =" + String.valueOf(post_sacount) +
                    " Post Delete Seq#=" + String.valueOf(post_ssn)
    );
    dbx.close();
}

Wynik z pierwszego uruchomienia (tzn. brak bazy danych) :-

D/SEQACTSTATS: Initial Rowcount=0 Initial Seq#=0 Post Delete Rowcount =0 Post Delete Seq#=0

Z kolejnego przebiegu (po dodaniu 40 wierszy) :-

D/SEQACTSTATS: Initial Rowcount=40 Initial Seq#=40 Post Delete Rowcount =0 Post Delete Seq#=0

Dodanie metody do wyświetlenia wszystkich wierszy, zgodnie z :-

private void listAllRows() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            salist = mTestDB.SequenceActionDaoAccess().getAll();
            getSequenceActionList(salist);
        }
    }).start();
}

Wraz z :-

@Override
public void getSequenceActionList(List<SequenceAction> sequenceActionList) {
    for (SequenceAction sa: sequenceActionList) {
        Log.d("SA","ID=" + String.valueOf(sa.getSequenceId()) + " AT=" + sa.getActionType() + " EI=" + sa.getExtraInfo());
    }
}

Wyniki w (pierwszy wiersz to ID=0 AT=X0 EI=Y0 tj. identyfikator kolumna pierwszego rzędu to 0 ):-

06-17 02:56:47.867 5526-5554/rt_mjt.roomtest D/SA: ID=0 AT=X0 EI=Y0
    ID=1 AT=X0 EI=Y0
    ID=2 AT=X0 EI=Y0
    ID=3 AT=X0 EI=Y0
    ID=4 AT=X1 EI=Y1
    ID=5 AT=X1 EI=Y1
    ID=6 AT=X1 EI=Y1
    ID=7 AT=X1 EI=Y1
06-17 02:56:47.868 5526-5554/rt_mjt.roomtest D/SA: ID=8 AT=X2 EI=Y2
    ID=9 AT=X2 EI=Y2
    ID=10 AT=X2 EI=Y2
    ID=11 AT=X2 EI=Y2
    ID=12 AT=X3 EI=Y3
    ID=13 AT=X3 EI=Y3
    ID=14 AT=X3 EI=Y3
    ID=15 AT=X3 EI=Y3
    ID=16 AT=X4 EI=Y4
06-17 02:56:47.869 5526-5554/rt_mjt.roomtest D/SA: ID=17 AT=X4 EI=Y4
    ID=18 AT=X4 EI=Y4
    ID=19 AT=X4 EI=Y4
    ID=20 AT=X5 EI=Y5
    ID=21 AT=X5 EI=Y5
    ID=22 AT=X5 EI=Y5
    ID=23 AT=X5 EI=Y5
    ID=24 AT=X6 EI=Y6
    ID=25 AT=X6 EI=Y6
    ID=26 AT=X6 EI=Y6
    ID=27 AT=X6 EI=Y6
06-17 02:56:47.870 5526-5554/rt_mjt.roomtest D/SA: ID=28 AT=X7 EI=Y7
    ID=29 AT=X7 EI=Y7
    ID=30 AT=X7 EI=Y7
    ID=31 AT=X7 EI=Y7
    ID=32 AT=X8 EI=Y8
    ID=33 AT=X8 EI=Y8
    ID=34 AT=X8 EI=Y8
    ID=35 AT=X8 EI=Y8
    ID=36 AT=X9 EI=Y9
    ID=37 AT=X9 EI=Y9
    ID=38 AT=X9 EI=Y9
    ID=39 AT=X9 EI=Y9
  • Uwaga:wyniki mogą być dziwne, ponieważ wiele wątków działa bez kontroli/sekwencjonowania.

addSomeData użyta metoda będąca :-

private void addSomeData() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            SequenceAction sa = new SequenceAction();
            for (int i=0; i < 10; i++) {
                sa.setSequenceId(0);
                sa.setActionType("X" + String.valueOf(i));
                sa.setExtraInfo("Y" + String.valueOf(i));
                mTestDB.SequenceActionDaoAccess().insertSingleRow(sa);
            }
        }
    }) .start();
}

Dodanie do komentarzy:-

„Wierzę, że musisz wejść przed Room…” – masz na myśli wykonanie kodu SQL, który czyści bieżący indeks przed utworzeniem instancji bazy danych Roomdatabase? - duch

niekoniecznie, ale zanim Roomotworzy bazę danych, która jest zanim spróbujesz coś z nią zrobić. Dodano kod wywołujący (w działaniach Overidden onStart() metoda ) z pewnym dostępem Room Db do addSomeData jest wywoływany natychmiast po. –MikeT

Oto przykład wywołania metody resetSequenceAction po utworzeniu instancji RoomDatabase, ale przed użyciem jej do uzyskania dostępu/otwarcia bazy danych (addSomeData otwiera już utworzoną bazę danych i wstawia 10 wierszy) :-

@Override
protected void onStart() {
    super.onStart();
    mTestDB = Room.databaseBuilder(this,TestDatabase.class,TestDatabase.DBNAME).build(); //<<<< Room DB instantiated
    resetSequenceAction(); //<<<< reset the sequence (adding trigger if needed)
    addSomeData(); // This will be the first access open
    addSomeData();
    addSomeData();
    addSomeData();
    listAllRows();


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Android - SQLite - WYBIERZ MIĘDZY Date1 A Date2

  2. Wyszukiwanie z akcentem w sqlite (Android)

  3. Sqlite nie wstawia danych do drugiej tabeli

  4. Jak odczytać numer wersji z pliku bazy danych w systemie Android, który jest umieszczony w folderze zasobów

  5. IllegalStateException:baza danych już zamknięta (przy użyciu ViewPager)