How to: Utilizar SQLite con Xamarin en iOS y Android

En muchas de las aplicaciones de dispositivos móviles tenemos la necesidad de trabajar con información de forma desconectada ya que existe una buena posibilidad de que el dispositivo tenga problemas para conectarse con nuestros servicios web a falta de una conexión a internet.

SQLite es un pequeño sistema de gestión de base de datos que no depende de un servidor y que almacena nuestra información en el dispositivo de una forma más sencilla y con la ventaja de poder utilizar LINQ para realizar consultas.

Este post veremos cómo utilizarlo con Xamarin en un proyecto portable para Android y para iOS.
Como primer paso necesitamos instalar el siguiente paquete desde Nuget en cada uno de los proyectos a través de la consola de paquetes de Nuget.

Install-Package sqlite-net-pcl  

Después crearemos una interfaz a la cual llamaremos ISQLite y la cuál debe tener un solo método que se encargará de obtener la conexión al archivo desde las diferentes plataformas.

//Declaración en PCL
public interface ISQLite  
{
   SQLiteConnection GetConnection();
}

Ahora debemos hacer la implementación dentro de nuestros proyectos, iniciemos por Android donde debemos colocar el siguiente código.

//Implementación en android
public class SQLite : ISQLite  
{
   public SQLiteConnection GetConnection()
   {
       string documentPath =
             Environment.GetFolderPath(Environment.SpecialFolder.Personal);

       string libraryPath = Path.Combine(documentPath, "..", "Library");

       Directory.CreateDirectory(libraryPath);

       var path = Path.Combine(libraryPath, CommonKeys.FileName);

       return new SQLiteConnection(path);
   }
}

Además, debemos agregar el siguiente atributo a nivel de namespace para utilizar los servicios de dependencia.

[assembly: Dependency(typeof(SQLite))]

Ahora veamos la siguiente implementación dentro del proyecto de iOS.

//Implementación en iOS
public class SQLite : ISQLite  
{
   public SQLiteConnection GetConnection()
   {
       string documentPath =
             Environment.GetFolderPath(Environment.SpecialFolder.Personal);

       string libraryPath = Path.Combine(documentPath, "..", "Library");

       Directory.CreateDirectory(libraryPath);

       var path = Path.Combine(libraryPath, CommonKeys.FileName);

       return new SQLiteConnection(path);
    }
}

Es necesario también agregar el siguiente atributo a nivel de namespace para poder utilizar también los servicios de dependencia.

[assembly: Dependency(typeof(SQLite))]

Ahora he creado un pequeño contexto para crear nuestra base de datos y además para obtener la conexión haciendo uso de los servicios de dependencia de Xamarin.

 public class DataBaseContext
 {
   public bool CreateDataBase()
   {
     try
     {
        using (var connection = GetConnection())
        {
            //Debes crear aquí cada una de las tablas que necesites
            connection.CreateTable<LicensePlate>();
         }
      }
      catch (Exception)
      {
          return false;
      }
      return true;
   }

   public SQLiteConnection GetConnection()
   {
      //Obtienes la implementación del contrato
      return DependencyService.Get<ISQLite>().GetConnection();
   }
}

Después crearemos un pequeño repositorio (debes modificarlo a tus necesidades) para poder realizar nuestras operaciones con los datos además de asegurarnos que nuestras operaciones sean thread safe.

//Repositorio en PCL
public class PlateRepository : IPlateRepository  
{
    private readonly DataBaseContext dataBaseContext;
    private static object locker = new object();

    public PlateRepository(DataBaseContext dataBaseContext)
    {
        this.dataBaseContext = dataBaseContext;
    }

    public IEnumerable<LicensePlate> LicensePlates => GetAll();

    public void Add(LicensePlate licensePlate)
    {
       lock (locker)
       {
          using (var connection = dataBaseContext.GetConnection())
          {
             connection.Insert(licensePlate);
          }
        }
    }

    public void Update(LicensePlate licensePlate)
    {
      lock (locker)
      {
         using (var connection = dataBaseContext.GetConnection())
         {
            connection.InsertOrReplace(licensePlate);
         }
      }
    }

    public void Delete(int id)
    {
       lock (locker)
       {
          using (var connection = dataBaseContext.GetConnection())
          {
             var item = connection.Table<LicensePlate>().FirstOrDefault(p => p.Id == id);
             if (item != null)
             {
                connection.Delete(item);
             }
          }
       }
    }

    public IEnumerable<LicensePlate> GetAll()
    {
       lock (locker)
       {
          using (var connection = dataBaseContext.GetConnection())
          {
              return connection.Table<LicensePlate>().ToList();
          }
       }
    }
}

Ahora podremos almacenar información en nuestros dispositivos, solo debes tener en cuenta que en algunas ocasiones estas operaciones consumen recursos y debes mantenerte al pendiente de la optimización de los recursos.

¿Cuéntame cuál ha sido tu experiencia con SQLite?

¡Saludos!