Xamarin Forms y Entity Framework Core SQLite, Persistencia y Acceso a Datos Locales en dispositivos móviles
Tags: csharp, xamarin, mobile, efcore
Published: 2019-12-17 07:02:20

Esta publicación forma parte del segundo calendario #AdvientoXamarin en español, una iniciativa liderada por Luis Beltrán.

A continuación les traigo un aporte sencillo pero no menos importante en el desarrollo de aplicaciones con Xamarin Forms, estoy seguro que en más de una ocasión hemos necesitado guardar información en una base de datos local dentro del dispositivo móvil y regularmente con el motor de Base de Datos SQLite tal cuál es el caso en esta implementación. A la hora de trabajar con datos para los desarrolladores .NET una opción muy familiar es Entity Framework debido a que puedes utilizarlo en diversas soluciones .NET tales como Proyectos de Consola, Windows Form, ASP.NET Web Forms, ASP.NET MVC, WebApis, WPF, UWP, etc. Obviamente a la lista anterior debes incluir aplicaciones móviles multiplataforma con Xamarin Forms.

**EF Core**
Entity Framework es un ORM (object-relational mapper) que permite a los desarrolladores trabajar con bases de datos utilizando objetos .NET.

Microsoft define Entity Framework (EF) Core como una versión ligera, extensible, de código abierto y multiplataforma de la popular tecnología de acceso a datos Entity Framework, EF Core soporta numerosos tipos de bases de datos tales como: SQLite, SqlServer, MySQL, Oracle, PostgreSQL, Firebird, etc. 
En este post demostraremos lo fácil que es utilizar EF Core en aplicaciones de Xamarin Forms para acceder a una base de datos local SQLite en las plataformas Android y iOS.

> **Nota:** Aunque esta implementación utiliza el patrón de arquitectura de software MVVM, la idea principal es demostrar el fácil acceso a datos y todo el provecho que le puedes sacar a EF Core, más aún si haz tenido experiencia con EF Core en otro tipo de soluciones .NET

* * *

> Esta es una simple implementación que trata de como almacenar registros en una Base de Datos SQLite, utilizaré los modelos Albumes y Artistas que he utilizado en post anteriores, crearemos una vista que contenga un formulario para crear albumes y posteriormente una vista que contenga un elemento de lista para mostrar los albumes almacenados en la Base de Datos.

Empezaremos creando un nuevo proyecto de Xamarin Forms en Visual Studio 2019.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/v9r7nbvo7m7fcucrv24w.PNG)

Teniendo nuestro proyecto creado la primero será agregar el paquete Nuget Microsoft.EntityFrameworkCore.Sqlite en el proyecto compartido de Xamarin Forms.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/qzqn25p3r9tbhegiveq2.PNG)

Ahora vamos a estructurar el código del proyecto compartido creando los siguientes directorios:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/0wy87euafwypalftoer7.PNG)

> **Nota:** La página MainPage.xaml que se crea por defecto al crear el proyecto fue movida al directorio Views, el namespace también fué modificado de XamEFCore que hace referencia a la raíz en el proyecto compartido a XamEFCore.Views y de la misma manera en el codebehind MainPage.xaml.cs.

El siguiente paso es crear un clase que sirva como contexto de datos, si ya haz trabajado con otras soluciones .NET como MVC, WebApis, etc, seguramente esto te será muy familiar. 
El contexto de datos es una clase en una solución .NET que hereda de la clase DbContext contenida en el namespace System.Data.Entity.DbContext y nos permite realizar las siguientes tareas:  
- Administrar la conexión de la base de datos
- Configurar modelos y relación
- Consultar base de datos
- Guardar datos en la base de datos
- Configurar el seguimiento de cambios
- Almacenamiento en caché
- Gestión de transacciones

Crearemos la clase contexto la llamaré AppDbContext y heredará de la clase DbContext, no olvidar agregar la referencia a Microsfot.EntityFrameworkCore.
Crearemos un atributo propio de la clase AppDbContext que nos servirá para setear la ruta y el nombre de la base datos para cada plataforma en este caso Android y iOS, este valor lo recibiremos mediante el método constructor de este contexto, seguidamente exponemos las propiedades DbSet que representan colecciones de las entidades especificadas en el contexto y sobreescribimos el método OnConfiguring para indicarle a EF Core que utilizaremos SQLite mediante el optionsBuilder pasandole como parámetro la ruta y el nombre de la base de datos que ya recuperamos y asignamos al atributo DbPath. 

> Nota: La ruta debe obtenerse en tiempo de ejecución.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/cybtse01qgzy84d8n34v.PNG)
  
En el siguiente paso vamos a recuperar la ruta en donde se almacenará la base datos específicamente para cada plataforma, debemos tomar en cuenta que el manejo de archivos y directorios es independiente para cada plataforma por lo que el almacenamiento de la base de datos se maneja de diferente manera tanto en Android como en iOS. Utilizaremos el Servicio de Dependencias (Dependency Service) de Xamarin Forms que nos permitirá implementar funcionalidades nativas para cada plataforma en este caso recuperar la ruta de almacenamiento de la base de datos, a grandes rasgos, Dependency Service consiste en crear una interface en el proyecto compartido e implementar esa interface en cada proyecto nativo con funcionalidades nativas para lograr comportamientos o funcionalidades propias de cada sistema operativo. 
Sabiendo lo anterior procedemos y en el proyecto compartido de Xamarin Forms crearemos una interface en el directorio Interfaces y la llamaremos IConfigDataBase la cuál únicamente contendrá un método que retorna un string que hace referencia a la ruta de almacenamiento de la base de datos y recibe un parámetro tipo string que hace referencia al nombre de la base de datos, cada implementación de esta interface se encargará de encadenar o combinar la ruta y el nombre para devolver un único string.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/7j37x20koev7hla4f0om.PNG)

Ahora vamos a implementar la interface anterior en el proyecto de Xamarin.Android, crearemos un directorio llamado Implementations que contendrá una clase llamada ConfigDataBase e implementamos el método GetFullPath especifícamente para Android.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/yjsjkikd6fvel6km9swo.PNG)

Realizaremos nuevamente el paso anterior pero esta vez para el proyecto Xamarin.iOS.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/nnecsjnulg016qsr1edz.PNG)

En el siguiente paso vamos a obtener una instancia del contexto de datos cuando se inicia la aplicación, esto garantiza que cuando ésta se ejecute por primera vez, independientemente de la plataforma en la que corra en tiempo de ejecución obtendremos la ruta de almacenamiento de la base de datos y se la mandaremos al método constructor del contexto de datos, para ello iremos al codebehind de App.xaml, escribiremos un método Static que regresará una nueva instancia del contexto, utilizamos el Dependency Service para obtener la ruta de almacenamiento de cada plataforma, seguidamente utilizaremos ese método Static en el método constructor y crearemos la base de datos con la instrucción Database.EnsureCreated().

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/4s5lom6ysaq2cnt6xb92.PNG)

Crearemos una clase que nos sirva como Servicio para acceder y realizar operaciones a la base de datos mediante EF Core y Linq, en este ejemplo nos centraremos en Crear y Listar objetos tipo Album, la clase se llamará DBDataAccess y estará dentro del directorio Services.
Obtenemos el contexto creado en el inicio de la aplicación y lo utilizamos para el manejo de objetos.

El método Create devuelve un bool y su valor depende de, si el objeto se creó correctamente.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/e5xp57pp2v178gb3r2kh.PNG)

El método Get es un método genérico que devuelve una lista de objetos y recibe 3 parámetros: parámetro 1 una condición, parámetro 2 ordenar por algún atributo propio del modelo y parámetro 3 la relación con otro modelo en este caso Artista.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/hk0dq56us40cbxyh8ete.PNG)

Realicé unas modificaciones para crear un ListView con dos opciones de menú crear y listar registros y se ve de la siguiente manera:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/8wbtb5rtx2azuctorshf.PNG)

> Nota: No entraré en detalles en cuanto al código de la Vista y el ViewModel asociado a la vista principal, puedes revisar el código en el repositorio de github.

Ahora crearemos en el directorio Views una Vista llamada AlbumPage aquí agregaremos un formulario para ingresar datos de Albumes y que estos se almacenen en la base de datos, previamente crearemos una clase llamada AlbumesViewModel en el directorio ViewModels, esto para poder agregar el BindingContext mediante código XAML en la vista.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/ci44inom8qgbyjwref22.PNG)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/q0xoul8ggrkvbey7zugm.PNG)

En la clase AlbumesViewModel crearemos la propiedades a enlazar mediante Binding con la Vista.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/a41wa1ov946j7748bl2u.PNG)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/ebdzy267sgm2q9fkl79m.PNG)

Crearemos el Command que se ejecutará cuando presionemos el Button Guardar, y utilizaremos el DataService de Albumes e invocamos al método Create y le pasamos el nuevo objeto Album que construimos a partir de los datos ingresados en el formulario.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/01tkyi17w3x23x9lu720.PNG)

Nuestra View para crear Albumes se verá de la siguiente manera:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/xqn68vx7lszbj6xw8gdc.PNG)

Llenamos el formulario.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/dn4r3k5y2rxev37h9vxe.PNG)

> Nota: El Picker de Artistas se carga mediante una lista de Artistas almacenada en la base de datos, utilicé un método temporal para crear dichos artistas en la tabla Artista, lo utilice únicamente para tener datos en dicha tabla, en otro escenario real esa lista podría venir de un WebApi o cualquier otra fuente de datos, no haré énfasis en esa funcionalidad, puedes revisar el código en el repositorio de github.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/rmiynubje8qctw3qkjo4.PNG)

Al presionar el Button Guardar se ejecuta el Command y el resultado es el siguiente:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/2ettyr8yom105uuw77um.PNG)

Ya es posible almacenar Albumes, el siguiente paso es mostrar un ListView con la lista de Albumes recuperada de la base de datos.

Crearemos una nueva View en el directorio Views y la llamaremos AlbumesPage.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/lbke8xvz544jl9mracqj.PNG)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/25gojoipcoqlii52f98k.PNG)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/yiwyvyp5i3p2q4h02esa.PNG)

> Nota: Esta View utiliza el mismo ViewModel en su propiedad BindingContext.

Ahora crearemos un método para recuperar esa lista de Albumes almacenada en la tabla Albumes de la base de datos y lo invocaremos en el método constructor de AlbumesViewModel.

El resultado es el siguiente:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/kd06gl6lycge69z84hn7.PNG)

Guardamos más Albumes en la base de datos y podremos visualizar como el ListView crece.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/sxw5wprrx2ytjcvvnxto.PNG)

## Conclusión
Personalmente como desarrollador .NET encuentro muchas ventajas sobre el uso de Entity Framework Core para manipular datos y bases de datos, el rendimiento de EF Core ha mejorado exponencialmente con respecto a versiones anteriores, además manipular los datos como objetos y realizar consultas mediante Linq es genial y más si previo a utilizarlo con Xamarin Forms lo utilizas en otras soluciones .NET 

Link al repositorio en GitHub: 
https://github.com/EbarriosCode/Xamarin-y-Entity-Framework-Core-SQLite

Referencias: 
https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/ef/overview
https://docs.microsoft.com/es-es/ef/ef6/fundamentals/working-with-dbcontext
https://www.entityframeworktutorial.net/efcore/entity-framework-core-dbcontext.aspx