Curso Básico de Xamarin: Implementando bases de datos locales con SQLite
En este tutorial aprenderás a almacenar la información de tu proyecto de Xamarin.Forms en bases de datos locales con SQLite.
NOTA: El código fuente de este proyecto está disponible en mi repositorio de GitHub
Paso 1. Abre Visual Studio 2019 y selecciona Crear un nuevo proyecto.
Paso 2. Busca el tipo de proyecto Mobile App (Xamarin.Forms), selecciónala y da clic en Siguiente:
Paso 3. En el nombre de proyecto escribe HarryPotterApp, asegúrate de seleccionar una ruta corta para la ubicación de tu solución y da clic en Crear:
Paso 4. Selecciona la plantilla Blank (proyecto vacío), selecciona las plataformas que deseas probar y da clic en OK:
Paso 5. Espera a que se genere la solución con los proyectos .NET Standard y el de cada plataforma. Da clic derecho en el proyecto HarryPotterApp y selecciona Administrar paquetes Nuget para la solución:
Paso 6. El paquete que necesitas para implementar el almacenamiento de información en una base de datos local para tu app móvil de Xamarin.Forms es SQLite-Net-PCL de Frank Krueger. Instálalo en todos los proyectos de tu solución.
Paso 7. Adicionalmente, instala Acr.UserDialogs, el cual es un paquete útil para mostrar cuadros de diálogo, mensajes, ventanas de petición de datos y confirmación al usuario, etc.
Paso 8. También actualiza todos los paquetes de tu solución, dado que utilizaremos el control CollectionView, el cual requiere Xamarin.Forms 4.3
Paso 9. Ahora, da clic derecho en el proyecto HarryPotterApp y agrega 4 carpetas: Data, Models, ViewModels y Views.
Paso 10. En la carpeta Models agrega la clase HPCharacter, la cual será utilizada como tabla (y modelo). Sus campos (propiedades) aparecen a continuación, resaltando que tenemos que agregar el atributo KeyAttribute a aquella propiedad que actuará como llave primaria de nuestra tabla.
Paso 11. Ahora, en la carpeta Data agrega la clase DatabaseContext, la cual contiene todos los elementos necesarios para interactuar con la base de datos (mejor aún, de forma genérica, por lo que te sirve para todas las tablas que maneje tu aplicación):
- En el constructor se establece una conexión a un archivo local (la base de datos indicada en el parámetro dbPath), además de crear la tabla HPCharacter (si ya existe, no ocurre nada).
- El método GetItemsAsync devuelve todos los elementos de una tabla
- FilterItemsAsync muestra que con SQLite también es posible ejecutar instrucciones SQL (en este caso, una consulta genérica).
- El método GetItemAsync devuelve el elemento que tenga la llave primaria (id) especificada.
- SaveItemAsync inserta o actualiza un registro, dependiendo el valor de isInsert.
- Finalmente, DeleteItemAsync remueve un registro de la tabla.
El código de esta clase es:
Paso 12. De una vez modificamos App.xaml.cs, en donde por medio del patrón Singleton vamos a crear un objeto Context que servirá de conexión a nuestra base de datos. Es en este lugar donde indicamos la ruta del archivo donde se almacenará la información. Observa el código:
¡Básicamente esto es todo lo que necesitamos para implementar el almacenamiento por medio de bases de datos locales en nuestras apps móviles con Xamarin! El resto del código es cómo realices las llamadas. Nosotros lo haremos con MVVM, ¡vamos a darle entonces!
Paso 13. Crea la clase BaseViewModel (que ya conoces) en la carpeta ViewModels. Su código se muestra a continuación.
Paso 14. Ahora, damos paso a CharacterViewModel, que contiene las mismas propiedades que el modelo HPCharacter pero con el código necesario para notificar a la vista cuando el valor de algún atributo sea modificado. Además, cuenta con lo siguiente:
- Un constructor vacío (no lo remuevas, se ocupa en otro ViewModel).
- Un constructor para asignar las propiedades desde un Model
- El método GetCharacter que construye un Model a partir de las propiedades
Observa el código:
CharacterViewModel será utilizado ampliamente por el resto de la aplicación.
Paso 15. Ahora genera la clase CharactersListViewModel, cuyo código se explica a continuación:
- La lista observable Characters contiene una colección de CharacterViewModels y servirá para cargar un CollectionView que muestre todos los datos que van siendo almacenados en la base de datos.
- SelectedCharacter es una referencia al elemento seleccionado de la lista por parte del usuario.
- El comando SearchByNameCommand tiene un doble propósito, dependiendo del valor que se pase como parámetro al ejecutarlo. Si es cadena vacía, llama al método LoadData para cargar todos los registros de la tabla (ver método GetItemsAsync). Si la cadena tiene algún valor, se llama al método FilterItemsAsync para buscar registros que coincidan con la búsqueda.
- El comando GoToDetailsCommand se utiliza para navegar a otra página que utilizará CharacterDetailsViewModel (una clase que creamos en el siguiente paso) como contexto de enlace, enviando como parámetro SelectedCharacter si el usuario seleccionó un elemento de la lista.
- El comando AddNewCharacterCommand también navegará a la misma página que el comando anterior utilizando un CharacterDetailsViewModel, pero en este caso se enviará una nueva instancia de CharacterViewModel porque se desea crear un nuevo registro.
Observa el código:
Paso 16. El último ViewModel a crear es CharacterDetailsViewModel, cuyo código se explica así:
- CharacterVM es una instancia de CharacterViewModel que se utilizará para guardar o eliminar un registro en la base de datos.
- SaveCharacterCommand es un comando para registrar información. Dependiendo el valor de _id determina si la operación es de inserción o actualización de datos.
- DeleteCharacterCommand es un comando para eliminar un registro de la tabla, previa confirmación del usuario.
Observa el código:
Paso 17. Ahora vamos con las vistas. La primera de ellas es CharactersListView, la cual es un ContentPage. Comenzamos por su code-behind, en el que simplemente hacemos dos cosas:
- Asignar el BindingContext a una instancia de CharactersListViewModel.
- Recargar la lista de datos cada vez que se navegue a esta página (para ello se sobreescribe el evento OnAppearing).
Paso 18. El código XAML de la interfaz se explica a continuación y se muestra debajo:
- Un botón para Agregar un Nuevo Personaje. Al presionarlo, se pasa una instancia de la página de destino como parámetro del comando.
- Un CollectionView para mostrar los datos que vayamos registrando en nuestra aplicación. Observa las diferentes propiedades asignadas: ItemsSource (la fuente de datos), SelectedItem (el elemento seleccionado por el usuario), SelectionChangedCommand (el comando que se ejecutará cada vez que se seleccione un elemento de la lista), SelectionChangedCommandParamenter (una instancia de la página de destino a la que se navegará al seleccionar un registro), SelectionMode (obligatorio establecerlo, pues por defecto tiene el valor None) y EmptyView (el mensaje que aparece cuando no hay datos).
Paso 19. La última vista es CharacterDetailsView, que también es un ContentPage y tiene el código XAML mostrado. Esta interfaz es relativamente sencilla, contiene los controles necesarios para registrar un nuevo personaje o editar la información de uno ya existente, así como los botones para guardar o eliminar los datos.
Paso 20. Ya casi para finalizar, modifica el constructor de App.xaml.cs para que la vista CharactersListView sea cargada cuando se ejecuta la app (el código respectivo lo puedes ver en el Paso 12 de este tutorial).
Paso 21. Si vas a probar la aplicación en Android, requieres inicializar el plugin de Acr.UserDialogs, simplemente agrega la instrucción Acr.UserDialogs.UserDialogs.Init(this); antes de la llamada a Forms.Init() en el método OnCreate de MainActivity (localizado en el proyecto HarryPotterApp.Android)
Paso 22. ¡Compila y ejecuta la aplicación! Si no hay errores, verifiquemos su correcto funcionamiento.
En este tutorial aprendiste a implementar bases de datos locales con SQLite en una app de Xamarin.Forms. En realidad es muy sencillo, pues solo requieres de agregar el paquete, crear la clase de contexto y el Singleton para utilizarlo en toda la aplicación; el resto es incorporarlo en tu ViewModel.
Espero que esta publicación haya sido de utilidad para tí.
Sin más por el momento, me despido. ¡Nos vemos en la próxima entrega!
¡Gracias por tu visita!
Luis