2013-05-13 14 views
5

Tworzyłem prostą aplikację sterowaną sqlite dla ios przy użyciu xamarin studio na mac.Baza danych nie utrzymywała się między kompilacjami z xamarin ios

Plik sqlite jest tworzony w folderze "osobistym" i jest przechowywany między kompilacjami, ale kiedy uruchomię aplikację, tabele utworzone w poprzedniej sesji debugowania zniknęły?

W moim kodzie, po sprawdzeniu, że plik istnieje, łączę się za pomocą sqliteconnection i utworzyć tabelę i wstawić wiersz z metodą execenonquery z obiektu command. Podczas gdy w tym samym kontekście mogę zapytać o tabelę przy użyciu drugiego obiektu polecenia, ale jeśli zatrzymam debuggera i zrestartuję tabelę i zniknę?

Czy mam plik w innym folderze, czy jest to ustawienie w Xamarin lub ios, aby zachować tabele? Czy nieumyślnie używam tabel tymczasowych w sqlite lub jaki może być problem?

Uwaga: do tej pory używam tylko wersji startowej Xamarin i debugowania na symulatorze iPhone'a.

public class BaseHandler 
{ 
    private static bool DbIsUpToDate { get; set; } 

    const int DB_VERSION = 1; //Created DB 

    const string DB_NAME = "mydb.db3"; 
    protected const string CNN_STRING = "Data Source=" + DB_NAME + ";Version=3"; 

    public BaseHandler() 
    { 
     //No need to validate database more than once on each restart. 
     if (DbIsUpToDate) 
      return; 

     CheckAndCreateDatabase(DB_NAME); 

     int userVersion = GetUserVersion(); 
     UpdateDBToVersion(userVersion); 

     DbIsUpToDate = true; 
    } 

    int GetUserVersion() 
    { 
     int version = 0; 

     using (var cnn = new SqliteConnection(CNN_STRING)) 
     { 
      cnn.Open(); 

      using (var cmd = cnn.CreateCommand()) 
      { 
       cmd.CommandText = "CREATE TABLE UVERSION (VERSION INTEGER);" + 
            "INSERT INTO UVERSION (VERSION) VALUES(1);"; 
       cmd.ExecuteNonQuery(); 
      } 

      using (var cmd = cnn.CreateCommand()) 
      { 
       cmd.CommandText = "SELECT VERSION FROM UVERSION;"; 
       var pragma = cmd.ExecuteScalar(); 
       version = Convert.ToInt32((long)pragma); 
      } 
     } 

     return version; 
    } 


    void UpdateDBToVersion(int userVersion) 
    { 
     //Prepare the sql statements depending on the users current verion 
     var sqls = new List<string>(); 

     if (userVersion < 1) 
     { 
      sqls.Add("CREATE TABLE IF NOT EXISTS MYTABLE (" 
        + " ID INTEGER PRIMARY KEY, " 
        + " NAME TEXT, " 
        + " DESC TEXT " 
        + ");"); 
     } 

     //Execute the update statements 
     using (var cnn = new SqliteConnection(CNN_STRING)) 
     { 
      cnn.Open(); 

      using (var trans = cnn.BeginTransaction(System.Data.IsolationLevel.ReadCommitted)) 
      { 
       foreach(string sql in sqls) 
       { 
        using (var cmd = cnn.CreateCommand()) 
        { 
         cmd.CommandText = sql; 
         cmd.ExecuteNonQuery(); 
        } 
       } 

       trans.Commit(); 

       //SetUserVersion(DB_VERSION); 
      } 

     } 
    } 

    protected string GetDBPath (string dbName) 
    { 
     // get a reference to the documents folder 
     var documents = Environment.GetFolderPath(Environment.SpecialFolder.Personal); 

     // create the db path 
     string db = Path.Combine (documents, dbName); 

     return db; 
    } 

    protected void CheckAndCreateDatabase (string dbName) 
    { 
     var dbPath = GetDBPath(dbName); 

     // determine whether or not the database exists 
     bool dbExists = File.Exists(dbPath); 

     if (!dbExists) 
      SqliteConnection.CreateFile(dbPath); 
    } 
} 

Ponownie, moim problemem jest to, że za każdym razem uruchomić debugger działa GetUserVersion ale UVERSION tabela nie jest zachowywane między sesjami. "File.Exists (dbPath)" zwraca true, więc CreateFile nie jest uruchamiany. Dlaczego baza danych jest pusta?

+1

Wygląda na to, że za każdym razem uruchamia się twój kod inicjujący. Czy możesz wysłać próbkę kodu? – Jason

Odpowiedz

0

Okazuje się, że było stworzenie connecti na obiekcie przy użyciu CNN_STRING, który po prostu miał nazwę-db zamiast pełnej ścieżki do bazy danych. Wyraźnie obiekt połączenia tworzy bazę danych, jeśli plik nie istnieje, więc plik File.Exists (...) może nie być potrzebny. Nie jestem naprawdę pewien, czy powinien to być tymczasowy db, jeśli pełna ścieżka nie jest dostarczona, ale wydaje się, że tak jest. Zmiana utworzenia obiektu połączenia na "datasource =" rozwiązała problem.

7

Jest to fragment kodu Użyłem uratować moich baz danych w symulatorze iOS i danych wydaje się utrzymywać między app kompiluje dobrze:

string documentsPath = Environment.GetFolderPath (Environment.SpecialFolder.Personal); 
string libraryPath = Path.Combine (documentsPath, "../Library/"); 
var path = Path.Combine (libraryPath, "MyDatabase.db3"); 

Możesz także sprawdzić klasę SQLite dla Xamarin off z Github: https://github.com/praeclarum/sqlite-net/tree/master/src

Oto poradnik jak używać wspomnianej klasy: http://docs.xamarin.com/recipes/ios/data/sqlite/create_a_database_with_sqlitenet

+0

Być może pytanie typu noob, ale używając znaków "/" dla ścieżki biblioteki, czy kod będzie przenośny między ios i androidem? Być może jest już ios specyficzne dla SpecialFolder.Personal? – Cliffhanger

+1

Możesz użyć instrukcji warunkowego kompilatora, aby obsłużyć różnicę między systemem iOS i Androidem: http://cl.ly/image/2X1l2b0N002G –

+0

Niezupełnie do tematu, ale jeśli masz problemy z Androidem, pamiętaj o sprawdzeniu opcja "zachowaj dane" w Xamarin: http://forums.xamarin.com/discussion/4878/database-sqlite-net-do-not-persist-between-build-on-monodroid – rufo

Powiązane problemy