2011-08-24 13 views
7

Używam tego DataBaseHelper.class i utknąłem w metodzie onUpgrade(). Nie wiem, jak ustalić numer wersji bazy danych. Mogę ustawić wersję na 1, przy pierwszym jej opublikowaniu i kiedy opublikuję aktualizację, mogę ustawić wersję na 2 (myDataBase.setVersion(2);). Ale będzie to tylko 2, o ile aplikacja będzie działać. Przy następnym uruchomieniu znów będzie 1. To samo dzieje się z private static int DATABASE_VERSION. Myślałem o przechowywaniu numeru wersji w dodatkowej tabeli, ale moim zdaniem nie jest to najlepsza praktyka.Baza danych onUpgrade - oldVersion - nowa wersja

Jak więc upewnić się, że numer wersji zwiększył się po aktualizacji i zachowuje ją (wartość, która została przypisana do private static int DATABASE_VERSION lub myDataBase.getVersion();)?

DataBaseHelper klasy:

public class DataBaseHelper extends SQLiteOpenHelper { 

    //The Android's default system path of your application database. 
    private static String DB_PATH = "/data/data/com.mydatabase.db/databases/"; 

    private static String DB_NAME = "database.sl3"; 

    private SQLiteDatabase myDataBase; 

    private final Context myContext; 


    // Do you need this? 
    private static int DATABASE_VERSION = 2; 
    // or is this correct: 
    // private static int DATABASE_VERSION = myDataBase.getVersion(); 


    /** 
    * Constructor 
    * Takes and keeps a reference of the passed context in order to access to 
    * the application assets and resources. 
    * 
    * @param context 
    */ 
    public DataBaseHelper(Context context) { 

     super(context, DB_NAME, null, DATABASE_VERSION); 
     this.myContext = context; 
    } 

    /** 
    * Creates an empty database on the system and rewrites it with your own 
    * database. 
    * */ 
    public void 
     createDataBase() throws IOException { 
     boolean dbExist = checkDataBase(); 

     if (dbExist) { 


     } 
     else { 

      //By calling this method and empty database will be created into the default system path 
      //of your application so we are gonna be able to overwrite that database with our database. 


      this.getWritableDatabase(); 


      try { 

       copyDataBase(); 

      } catch (IOException e) { 

       throw new Error("Error copying database"); 

      } 
     } 

    } 

    /** 
    * Check if the database already exist to avoid re-copying the file each 
    * time you open the application. 
    * 
    * @return true if it exists, false if it doesn't 
    */ 
    private boolean 
     checkDataBase() { 

     SQLiteDatabase checkDB = null; 

     try { 
      String myPath = DB_PATH + DB_NAME; 
      checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE); 

     } catch (SQLiteException e) { 

      //database does't exist yet. 

     } 

     if (checkDB != null) { 

      checkDB.close(); 

     } 
     return checkDB != null ? true : false; 
    } 

    /** 
    * Copies your database from your local assets-folder to the just created 
    * empty database in the 
    * system folder, from where it can be accessed and handled. 
    * This is done by transfering bytestream. 
    * */ 
    private void 
     copyDataBase() throws IOException { 

     //Open your local db as the input stream 
     InputStream myInput = myContext.getAssets().open(DB_NAME); 


     // Path to the just created empty db 
     String outFileName = DB_PATH + DB_NAME; 


     //Open the empty db as the output stream 
     OutputStream myOutput = new FileOutputStream(outFileName); 


     //transfer bytes from the inputfile to the outputfile 
     byte[] buffer = new byte[1024]; 
     int length; 
     while ((length = myInput.read(buffer)) > 0) { 
      myOutput.write(buffer, 0, length); 
     } 


     //Close the streams 
     myOutput.flush(); 
     myOutput.close(); 
     myInput.close(); 

    } 

    public void 
     openDataBase() throws SQLException { 

     //Open the database 
     String myPath = DB_PATH + DB_NAME; 
     myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE); 



     // Which parameters do I have to pass? 
     onUpgrade(myDataBase, DATABASE_VERSION, 2); 
    } 

    @Override 
    public synchronized void 
     close() { 

     if (myDataBase != null) 
      myDataBase.close(); 

     super.close(); 

    } 

    @Override 
    public void 
     onCreate(SQLiteDatabase db) { 

    } 

    @Override 
    public void 
     onUpgrade( SQLiteDatabase db, 
       int oldVersion, 
       int newVersion) { 

    Log.d ("onUpgrade first log", Integer.toString(myDataBase.getVersion())); 




    if (oldVersion == 1) { 

     // do something 


     // And then do this!? 
     DATABASE_VERSION = 2; 
     // or do this 
     myDataBase.setVersion(2); 
     Log.d ("onUpgrade sedond log", Integer.toString(myDataBase.getVersion())); 

    } 

    else { 
     Log.d("onUpgrade", "else-clause: Already upgraded!"); 
    } 



} 

Odpowiedz

11
// Do you need this? 
private static int DATABASE_VERSION = 2; 

Tak, trzeba to. (Nawet lepiej, spraw, aby był on również final.)

To powie helperowi bazy danych, jaka jest najnowsza wersja schematu bazy danych. Powinno to zostać poprawione w kodzie aplikacji i zwiększane za każdym razem, gdy zmieniasz schemat.

Po uruchomieniu aplikacji helper sprawdza w czasie wykonywania, czy pomysł na najnowszą wersję kodu jest taki sam, jak wersja, która była aktywna podczas tworzenia lub uaktualniania bazy danych. (To jest to, do czego służy db.getVersion().) Jeśli liczby nie są zgodne, wówczas pomocnik wie, że przechowywana baza danych jest nieaktualna w odniesieniu do kodu aplikacji, a zatem uruchamia procedurę aktualizacji.

Wygląda na to, że nie tworzysz bazy danych od podstaw, ale importujesz istniejącą bazę danych z zasobów. Kiedy robisz ten początkowy import, jest to czas, aby upewnić się, że przechowywana wersja pasuje do wersji Twojego kodu; albo zastosuj go bezpośrednio do pliku bazy danych w swoich zasobach, albo, jeśli masz pewność, że plik bazy danych w Twoich zasobach jest zgodny z kodem, zadzwoń pod numer setVersion(DATABASE_VERSION).

W żadnym wypadku nie powinieneś próbować modyfikować numerów wersji w procedurze onUpgrade(). Jest to zawsze wywoływane, jeśli wersje się nie zgadzają, a wszystko, co powinieneś tutaj zrobić, to wprowadzić wszelkie zmiany, które są konieczne, aby aktualizacja bazy danych była aktualna. Pomocnik będzie zarządzał przechowywaniem nowego numeru wersji po zakończeniu aktualizacji.

+0

Cześć Graham Borland! Masz rację Importuję istniejącą bazę danych z folderu zasobów i myślę, że to jest to, czego potrzebuję, a następnie aplikuję ją bezpośrednio do pliku bazy danych w Twoim asset_! Ale jak to zrobić? – BenjaminButton

+0

Przez _it_ miałem na myśli numer wersji. – BenjaminButton

+1

Mam to działa! W klasie createDataBase brakuje linii: 'public void createDataBase() wyrzuca wyjątek IOException {boolean dbExist = checkDataBase(); jeśli (dbExist) {/ * Ta linia: */this.getWritableDatabase();} ... ' Ponadto onUpgrade() jest wywoływana, gdy tworzony jest nowy obiekt klasy DataBaseHelper ** ale ** tylko wtedy, gdy baza danych numery wersji nie pasują. Oznacza to, że nie trzeba wywoływać "Aktualizuj" na własną rękę. Jeśli opublikujesz aktualizację swojej bazy danych, po prostu zwiększ jej wersję o jeden i zastosuj zmiany w metodzie onUpgrade(). Mam nadzieję, że pomaga każdemu! – BenjaminButton

1

Dodanie informacji do odpowiedzi Grahama Borlanda. Wyjaśnię w scenariuszu aplikacji, w której twoja baza danych znajduje się w folderze zasobów i skopiuj go do swojego folderu, jeśli nie jest tam obecny. Teraz, jeśli chcesz uaktualnić swoją aplikację o zaktualizowaną bazę danych. Należy ustawić

private final static int DB_VERSION=2;   // Database Version 

w klasie pomocnika bazy danych.

(Dowolna liczba całkowita, która powinna być czymś więcej niż pierwotnej wersji db który można ustawić initialy w tej klasie)

Potem trzeba dodać kod do ręcznego ONUPGRADE() W tym scenarion I overrite stary db z najnowszym.Możesz zmienić swój kod jako własnych upodobań

@Override 
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
     // TODO Auto-generated method stub 
      CopyNewDatabaseFromAsset(); 
    } 

Jeśli potrzebujesz żadnych wyjaśnień proszę umieszczać w komentarzu :)