viewdestroy supported samples platforms mvxasynccommand android ios sqlite xamarin mvvmcross

android - supported - mvxasynccommand



SqliteException ocupado iOS/Android Xamarin MVVMCross (1)

Parece que tienes algunas opciones:

  1. Crear una instancia solo de un SqliteDataService y pasarle una referencia a sus objetos Stocks y Valuations, esto parecería más sensato ya que ambos están operando en el mismo DB

  2. Cree una instancia de un objeto para su uso como un bloqueo fuera del servicio y pase una referencia al constructor SqliteDataService para que ambos servicios compartan el bloqueo. Creo que esto funcionaría, pero no soy experto en bloquear.

  3. Puede manejar la excepción Ocupado en un bloque try catch e iterar un contador para realizar un número máximo de intentos contra la base de datos con una breve espera cada vez para que tenga buenas posibilidades de conectarse. Si la base de datos sigue ocupada, seguirá recibiendo la excepción y esta solución es bastante desordenada.

  4. Reestructurar el DB para que las dos áreas estén separadas, esto probablemente no sea posible, pero vale la pena pensarlo.

En nuestra aplicación MVVMCross de Android e iOS estamos experimentando ocasionalmente SQLiteException: excepciones ocupadas.

Dado el código a continuación, tenemos varios repositorios cada uno de los cuales construye una instancia de la siguiente y una conexión asociada a la base de datos Sqlite. Imagine que tenemos un depósito de stocks y un repositorio de valoraciones, se crearán dos instancias de SqliteDataService: SqliteDataService con tipo Stocks y SqliteDataService con valoraciones de tipos, cada una de las cuales tiene una conexión con la base de datos Sqlite.

Las acciones en los repositorios pueden operar en subprocesos de fondo, lo que significa que podemos intentar insertar Stocks en la base de datos al mismo tiempo que las Valuaciones.

Ahora, dado que cada repositorio crea su propio SqliteDataService, el bloqueo de connectionObject solo protegerá a los mismos tipos de repositorio de acceder a la base de datos al mismo tiempo en lugar de proteger Stocks and Valuations para que accedan a la base de datos al mismo tiempo.

Mis preguntas son:

¿Es válido crear conexiones por depósito y, en caso afirmativo, cómo protegernos de SqliteException: busy?

¿Hay un mejor patrón? es decir, ¿deberíamos crear una clase SqliteDataService no genérica que comparta la misma conexión entre hilos? Lo hemos intentado pero en Android experimentamos excepciones fatales.

¿Alguien tiene un patrón Sqlite DAL sólido para 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); } }