Entity Framework Core con Xamarin.Forms: SQLite de manera sencilla
¡Hola! Por lo general cuando desarrollamos una app móvil necesitamos almacenar información persistente, es decir, que siga ahí cuando volvamos a abrir la app. Esta información puede ser guardada localmente (es decir, en el dispositivo) o remotamente (en un servidor o en la nube por ejemplo). En el caso del almacenamiento local, normalmente la opción preferida es SQLite, un gestor de bases de datos relacionales muy ligero y poderoso a la vez que ya viene incluido en el sistema operativo. Dependiendo de las reglas de negocio, los datos locales pueden ser sincronizados posteriormente en una base de datos remota, ya sea en la nube o en un servidor (o también el proceso inverso, descargando los datos remotos hacia el repositorio local).
Si has desarrollado aplicaciones en C# tipo Windows Forms, WPF, ASP .NET, Web Api, UWP, etc. seguramente conoces Entity Framework, un framework ORM basado en .NET muy popular por su simplicidad y poder. Combinada con LINQ, puedes crear controladores que accedan a un almacén de datos de una manera ágil y sencilla. Su principal ventaja es que al proporcionar la conexión al proveedor de datos, los objetos (por ejemplo una tabla de base de datos) son mapeados a entidades (clases) que son creadas y agregadas a tu proyecto automáticamente.
Entity Framework Core es una extensión ligera y multiplataforma de Entity Framework que simplifica el acceso a un repositorio de datos (soporta varios: SQLite, SqlServer, ¡incluso MySQL, PostgreSQL y Firebird!). Y en este post aprenderás lo fácil que es utilizar EF Core en tus aplicaciones de Xamarin.Forms para acceder a una base de datos local en SQLite.
¿Preparado? ¡Comenzamos!
En primer lugar, crea un nuevo proyecto de Xamarin.Forms llamado SistemaEscolar.
Selecciona la estrategia de código compartido .NET Standard, así como Xamarin.Forms para nuestra tecnología de interfaz de usuario. Elige las plataformas que deseas soportar.
Una vez creado el proyecto, da clic derecho sobre la solución y selecciona Administrar paquetes Nuget para la solución. Agrega el paquete Microsoft.EntityFrameworkCore.Sqlite (versión 1.1.5) a todos los proyectos de tu solución.
Crea las siguientes carpetas en el proyecto SistemaEscolar (.NET Standard)
En la carpeta Helpers, agrega la clase Constantes, con el código siguiente:
En la carpeta Modelos, agrega la clase Escuela, con el siguiente código:
En la misma carpeta agrega la clase Alumno, con el código mostrado a continuación. Aquí hay que resaltar algo. Hay convenciones para que EF Core determine automáticamente qué campo es llave primaria y llave foránea en las entidades. En este caso, sin embargo, utilizaré los atributos para que se comprenda qué campos servirán para la relación entre tablas. También hay 3 formas diferentes de colocar el atributo ForeignKey.
A continuación accede a la carpeta Datos y crea primero la interfaz IBaseDatos, la cual solo contiene un elemento:
Posteriormente, agrega la clase BaseDatos en la misma carpeta, la cual implementa la interfaz recién creada. El código se muestra a continuación. Cabe resaltar que mediante DependencyService se obtiene la ruta física real donde se encuentra la base de datos (la ubicación es específica por plataforma):
En la carpeta Servicios genera una interfaz llamada IServicioBaseDatos, la cual contiene los elementos mostrados en el código. Si observas, estamos creando métodos genéricos, por lo que no será necesario crear métodos específicos por cada entidad (es decir, no necesitamos un BuscarAlumno, un BuscarEscuela, un AgregarAlumno, un AgregarEscuela, etc) sino que solo tenemos un método (por ejemplo, Agregar) que servirá para insertar registros en cualquier entidad de nuestra base de datos. ¡Solo 5 métodos!
(Aquí le agradezco a mi amiga Tere la idea de hacerlo genérico porque hace unos días estábamos trabajando sobre un proyecto de UWP que consume un WebApi y comenzamos creando los métodos para acceder a una tabla específica y me preguntó que si había que hacer eso por cada entidad -la base de datos tiene 18 tablas, así que tendríamos que generar ¡90 métodos!-. Obviamente, había que buscar una mejor solución… ¡Generics! Y bueno, no fue complicado crear esos métodos… traerse la idea a EntityFramework Core en una app de Xamarin fue realmente sencillo gracias a la experiencia adquirida… so… ¡thank you, Tere! ^^)
Regresamos al ejercicio, jeje. El siguiente paso es crear una clase llamada ServicioBaseDatos que precisamente implementa la interfaz recién creada.
NOTA: Seguramente estás pensando que en tu aplicación más de una vez necesitarás crear métodos específicos para personalizar alguna operación (realizar una búsqueda por un campo distinto al Id, validar datos antes de insertarlos en la base de datos, etc.). Por eso, los métodos han sido marcados como virtual, y te prometo que en la siguiente publicación vamos a crear una subclase para personalizar algún método (búsqueda de escuelas, verificar la fecha de nacimiento por ejemplo de un alumno) para que comprendas todo el potencial de esto… que si te fijas, ¡es básicamente aplicar los conceptos de Programación Orientada a Objetos!
Ahora procedemos a crear los elementos de interfaz de usuario. En la carpeta Páginas primero agregamos un ContentPage llamado PaginaEscuela. El código XAML es el siguiente:
Y su code-behind es:
A continuación creamos PaginaListaEscuelas, otro ContentPage, con el siguiente código:
Su código de C# respectivo es:
El siguiente paso es crear el ContentPage de PaginaAlumno, con el siguiente código XAML:
Y el código de C# mostrado a continuación:
La última página que crearemos de momento es el ContentPage para mostrar a todos los alumnos de una escuela, PaginaListaAlumnos.
Con el código de C# respectivo:
En App.xaml.cs establecemos la página de inicio, un stack de navegación y también definimos una conexión única a utilizar durante toda la ejecución de la aplicación. Por un lado, nos ahorramos abrir y cerrar la conexión (operación que puede ser costosa en ocasiones) y también aseguramos que todas las operaciones están en el mismo contexto (útil cuando queremos actualizar datos de tablas relacionadas).
El siguiente bloque de pasos consiste en obtener la ruta específica por plataforma donde se alojará la base de datos. Básicamente, en cada plataforma hay que crear una carpeta y dentro colocar una clase que obtenga la ruta física del archivo. El proceso es el mismo, lo que cambia es la ubicación de la base de datos. Realiza lo siguiente:
En el proyecto de Android, agrega la carpeta Datos y crea la clase BaseDatosAndroid dentro de ella, con el código siguiente:
En el proyecto de UWP también crea la carpeta Datos, y dentro crea una clase llamada BaseDatosUWP, la cual contiene el siguiente código:
Como seguro has intuido, en el proyecto de iOS crearás una clase llamada BaseDatosiOS dentro de una nueva carpeta llamada Datos. El código respectivo es:
Aunque en el caso del proyecto de iOS, es necesario configurar la clase AppDelegate. Agrega el espacio de nombres Microsoft.EntityFrameworkCore y la instrucción SQLitePCL.Batteries_V2.Init() antes del Init de Xamarin.Forms tal como se muestra en el código siguiente:
¡Eso es todo! Vamos a probar la aplicación, compila y ejecuta. ¡Veamos lo que sucede!
El proyecto está disponible en mi repositorio de GitHub para que lo descargues y verifiques su funcionamiento 🙂
(Pequeña nota: me falta actualizar unos archivos del repositorio, pero Visual Studio se puso a instalar actualizaciones, así que el commit lo haré cuando terminen xD)
En esta entrada aprendiste a desarrollar una app de Xamarin.Forms que almacena datos utilizando SQLite con la tecnología de Entity Framework Core para operaciones CRUD (acceso y manipulación de datos). En la siguiente entrada implementaremos una búsqueda de datos y también te mostraré cómo implementar una relación Many-to-Many, típica en muchas situaciones.