2013-05-13 5 views
5

Sto creando una semplice app SQLlite guidata per iOS utilizzando xamarin studio su un mac.Database non persistente tra build con xamarin ios

Il file sqlite viene creato nella cartella "personale" e viene mantenuto tra le build ma quando eseguo l'app le tabelle che ho creato nella precedente sessione di debug sono scomparse?

Nel mio codice, dopo aver verificato che il file esista, mi connetto utilizzando una connessione sqlitecreare una tabella e inserire una riga con il metodo executenonquery dall'oggetto comando. Mentre nello stesso contesto posso interrogare la tabella usando un secondo oggetto comando ma se interrompo il debugger e riavvio la tabella se n'è andato?

Dovrei avere il file in una cartella diversa, è un'impostazione in xamarin o ios per mantenere i tavoli? Uso involontariamente tabelle temporanee in sqlite o quale potrebbe essere il problema?

Nota: per il momento sto utilizzando solo la versione iniziale di xamarin e il debug sul simulatore iphone.

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); 
    } 
} 

Ancora una volta, il mio problema è che ogni volta che faccio funzionare il debugger viene eseguito GetUserVersion ma l'UVERSION tavolo non viene mantenuto tra le sessioni. "File.Exists (dbPath)" restituisce true, quindi CreateFile non viene eseguito. Perché il db è vuoto?

+1

Sembra che il codice di inizializzazione sia in esecuzione ogni volta. Puoi pubblicare un esempio di codice? – Jason

risposta

0

scopre che stavo creando il connecti sull'oggetto utilizzando il CNN_STRING che aveva appena il nome-db invece del percorso completo del db. Apperentemente l'oggetto connessione crea il database se il file non esiste, quindi File.Existe (...) potrebbe non essere necessario. Non sono davvero sicuro se dovrebbe essere un db temporaneo se il percorso completo non viene fornito, ma sembra essere il caso. La modifica della creazione dell'oggetto di connessione su "datasource =" ha risolto il problema.

7

Si tratta di un frammento di codice che ho usato per salvare le mie basi di dati nel simulatore iOS e il dato sembra persistere tra app compila bene:

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

Si consiglia inoltre di controllare la classe SQLite per Xamarin off di Github: https://github.com/praeclarum/sqlite-net/tree/master/src

Ecco un tutorial su come utilizzare detto classe: http://docs.xamarin.com/recipes/ios/data/sqlite/create_a_database_with_sqlitenet

+0

Forse una domanda noob ma usando i caratteri "/" per il percorso della libreria, il codice sarà portatile tra iOS e Android? Forse è già specifico di SpecialFolder.Personal? – Cliffhanger

+1

È possibile utilizzare istruzioni del compilatore condizionale come per gestire la differenza tra iOS e Android: http://cl.ly/image/2X1l2b0N002G –

+0

Non esattamente per l'argomento, ma se si verificano problemi in Android, assicurarsi di controllare il opzione 'conserva dati' in Xamarin: http://forums.xamarin.com/discussion/4878/database-sqlite-net-do-not-persist-between-build-on-monodroid – rufo