2015-04-22 16 views
6

Nella nostra app MVVMCross per Android e iOS stiamo riscontrando occasionalmente SQLiteException: eccezioni occupate.SqliteException occupato iOS/Android Xamarin MVVMCross

Dato il codice di seguito, abbiamo diversi repository ciascuno dei quali costruisce un'istanza di seguito e una connessione associata al database Sqlite. Immaginiamo di avere un deposito di titoli e un repository di valute, verranno create due istanze di SqliteDataService: SqliteDataService con tipo Stocks e SqliteDataService con tipi di valutazioni, ognuna delle quali ha una connessione al database Sqlite.

Le azioni sui repository possono operare su thread in background, il che significa che possiamo tentare di inserire azioni nel database contemporaneamente alle valutazioni.

Ora che ogni repository crea il proprio SqliteDataService, il blocco connectionObject protegge solo gli stessi tipi di repository dall'accesso al database allo stesso tempo anziché proteggere Stock e Valori dall'accesso al database nello stesso momento.

Le mie domande sono:

E 'valido per creare una connessioni per repository e se sì, come possiamo evitare il rischio di SqliteException: occupato?

Esiste uno schema migliore? cioè dovremmo creare una classe SqliteDataService non generica che condivide la stessa connessione tra thread? Abbiamo provato questo, ma su Android sperimentiamo eccezioni fatali.

Qualcuno ha un modello DAL solido Sqlite per Xamarin MVVMCross?

public class SqliteDataService<T> : IDataService<T> where T : new() 
{ 
    private static object lockObject = new object(); 

    private static object connectionObject = new object(); 

    private static ISQLiteConnection _connection; 

    private static SqliteDataService<T> _instance; 

    public SqliteDataService(ISQLiteConnectionFactory connectionFactory, string dbPath) 
    { 
     if (_connection == null) 
     { 
      _connection = connectionFactory.Create (dbPath); 
      _connection.CreateTable<T>(); 
     } 
    } 

    public static SqliteDataService<T> GetInstance(ISQLiteConnectionFactory connectionFactory, string dbPath) 
    { 

     if (_instance == null) 
     { 
      lock (lockObject) 
      { 
       _instance = new SqliteDataService<T> (connectionFactory, dbPath); 
      } 
     } 

     return _instance; 
    } 

    public void CreateTable<T>() 
    { 

    } 

    public void Insert(T value) 
    { 
     lock (connectionObject) { 
      _connection.Insert (value, typeof(T)); 
     } 
    } 

    public void InsertAll(IEnumerable<T> values) 
    { 
     lock (connectionObject) { 
      _connection.Insert (values, typeof(T)); 
     } 
    } 

    public IEnumerable<T> Read(Expression<Func<T, bool>> predicate) 
    { 
     lock (connectionObject) { 
      return _connection.Table<T>().Where (predicate); 
     } 
    } 

    public T ReadFirst(Expression<Func<T, bool>> predicate) 
    { 
     lock (connectionObject) { 
      return Read (predicate).FirstOrDefault(); 
     } 
    } 

    public void Update(T value) 
    { 
     lock (connectionObject) { 
      _connection.Update (value, typeof(T)); 
     } 
    } 

    public void Delete(Expression<Func<T, bool>> predicate) 
    { 
     lock (connectionObject) { 
      var valuesToDelete = Read (predicate); 

      if (valuesToDelete == null) 
       return; 

      foreach (var value in valuesToDelete) { 
       _connection.Delete (value); 
      } 
     } 
+0

Hai risolto il problema? Si prega di inviare una risposta se è stato risolto. –

risposta

0

Suona come avete alcune opzioni:

  1. un'istanza di una sola SqliteDataService e passa un riferimento ad esso per entrambe le scorte e oggetti di valutazioni, questo sembrerebbe più ragionevole in quanto entrambi sono funziona sullo stesso DB

  2. Istanziare un oggetto da utilizzare come blocco all'esterno del servizio e passare un riferimento nel costruttore SqliteDataService in modo che il blocco sia condiviso da entrambi i servizi. Credo che funzionerebbe, ma non sono esperto nel bloccare.

  3. È possibile gestire l'eccezione Occupato in un blocco catch try e iterare un contatore per effettuare un numero massimo di tentativi contro il database con una breve attesa ogni volta in modo da avere una buona possibilità di connessione. Se il DB rimane occupato si otterrà comunque l'eccezione e questa soluzione è piuttosto disordinata.

  4. Ristruttura il DB in modo che le due aree siano separate, probabilmente non è possibile, ma vale la pena di pensarci.

Problemi correlati