Ejercicio: Almacenamiento de datos de forma local con SQLite

Completado

En este ejercicio, usará SQLite para almacenar información localmente con una aplicación. En el escenario de ejemplo, decidió almacenar en caché los datos de la aplicación de red social para mejorar la capacidad de respuesta. Este ejercicio crea y usa una base de datos SQLite local para almacenar la información de las personas. Guarde el archivo de base de datos físico en el almacenamiento local.

En este módulo se usa el SDK de .NET 9.0. Asegúrese de que tiene instalado .NET 9.0 mediante la ejecución del siguiente comando en el terminal de comandos que prefiera:

dotnet --list-sdks

Aparecerá un resultado similar al del ejemplo siguiente:

8.0.100 [C:\Program Files\dotnet\sdk]
9.0.100 [C:\Program Files\dotnet\sdk]

Asegúrese de que aparezca una versión que comience en 9. Si no aparece ninguna o no se encuentra el comando, instale el SDK más reciente de .NET 9.0.

Abrir la solución de inicio

  1. Clone o descargue el repositorio del ejercicio.

    Nota:

    Es mejor clonar el contenido del ejercicio en una ruta de acceso de carpeta corta, como C:\dev, para evitar que los archivos generados por compilación excedan la longitud máxima de la ruta de acceso.

  2. Use Visual Studio para abrir la solución People.sln, que encontrará en mslearn-dotnetmaui-store-local-data>Personas, o la carpeta starter en Visual Studio Code.

    Nota:

    No intente ejecutar la aplicación todavía, el código está incompleto y producirá excepciones hasta que agregue los elementos que faltan más adelante en este ejercicio.

Definición de una entidad SQLite

  1. Abra el archivo Person.cs en la carpeta Modelos.

  2. Agregue una propiedad int denominada Id a la clase Person.

  3. Agregue una propiedad string denominada Name. La clase debería tener el siguiente aspecto:

    namespace People.Models;
    
    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    
  4. Guarde el archivo Person.cs.

Adición de la biblioteca SQLite

  1. Haga clic con el botón derecho en el nodo del proyecto People en el Explorador de soluciones de Visual Studio.

  2. En el menú contextual que aparece, seleccione Administrar paquetes NuGet.

  3. Busque y seleccione sqlite-net-pcl y, a continuación, seleccione Instalar.

    Recorte de pantalla que muestra el administrador de paquetes NuGet con la biblioteca sqlite-net-pcl seleccionada.

Si usa Visual Studio Code, abra el terminal y estos paquetes con los siguientes comandos:

dotnet add package sqlite-net-pcl

Adición de atributos de SQLite

  1. En el archivo Person.cs, agregue una directiva using para el espacio de nombres SQLite al archivo de la clase Person. Esta directiva permite usar los atributos de SQLite.

    using SQLite;
    
    namespace People.Models;
    
    public class Person
    {
        ...
    }
    
  2. Anote la clase Person con el atributo [Table] y especifique que el nombre de la tabla es people.

  3. Especifique la propiedad Id como clave principal. Anótela con los atributos [PrimaryKey] y [AutoIncrement].

  4. Agregue anotaciones a la propiedad Name. Especifique su MaxLength como 250. Especifique que cada valor de la columna debe ser Unique.

    Este es el aspecto que debería tener la clase completada:

    using SQLite;
    
    namespace People.Models;
    
    [Table("people")]
    public class Person
    {
        [PrimaryKey, AutoIncrement]
        public int Id { get; set; }
    
        [MaxLength(250), Unique]
        public string Name { get; set; }
    }
    
  5. Guarde el archivo Person.cs.

Conectarse a la base de datos

  1. Abra el archivo PersonRepository.cs.

  2. Examine la clase PersonRepository. Esta clase contiene código esqueleto incompleto con TODO marcadores en los que se agrega la funcionalidad para acceder a la base de datos.

  3. Agregue una directiva using para los espacios de nombres SQLite y People.Models al archivo de la clase PersonRepository.cs.

  4. Agregue un campo privado SQLiteConnection denominado conn a la clase, encima de la función Init.

  5. En la función Init, compruebe si conn no es igual a null. Si es así, ejecute "return" inmediatamente.

    if (conn != null)
        return;
    

    De esta forma, el código de inicialización de la base de datos SQLite solo se ejecuta una vez.

  6. Inicialice el campo conn para conectarse a la base de datos con la variable _dbPath.

  7. Use el método conn.CreateTable para crear una tabla para almacenar datos Person. Este es el aspecto que debería tener la función Init completada:

    using SQLite;
    using People.Models;
    ...
    
    private SQLiteConnection conn;
    ...
    private void Init()
    {
       if (conn != null)
          return;
    
       conn = new SQLiteConnection(_dbPath);
       conn.CreateTable<Person>();
    }
    

Inserción de una fila en la base de datos

  1. En la clase PersonRepository, busque el método AddNewPerson.

  2. Para insertar un nuevo objeto Person, reemplace el comentario TODO en este método por código. El código llama primero a Init para comprobar que se inicializa la base de datos y, a continuación, usa el método SQLiteConnection del objeto Insert. Establezca la variable result en el valor que devuelve el método Insert, como se muestra en el código siguiente:

    public void AddNewPerson(string name)
    {
        int result = 0;
        try
        {
            // enter this line
            Init();
    
            // basic validation to ensure a name was entered
            if (string.IsNullOrEmpty(name))
                throw new Exception("Valid name required");
    
            // enter this line
            result = conn.Insert(new Person { Name = name });
            ...
        }
        ...
    }
    

Recuperación de filas de la base de datos

  1. En la clase PersonRepository, busque el método GetAllPeople.

  2. Llame a Init para comprobar que se inicializa la base de datos.

  3. Use el método Table\<T> genérico para recuperar todas las filas de la tabla. Especifique Person como parámetro de tipo.

  4. Use el método de extensión ToList() para convertir el resultado en una colección List\<Person> y devolver esta colección.

  5. Agregue control de errores encapsulando el código en un bloque try-catch. Si se produce un error, establezca la propiedad StatusMessage en la propiedad Message de la excepción y devuelva una colección vacía. El método completado debería tener el siguiente aspecto:

    public List<Person> GetAllPeople()
    {
       try
       {
          Init();
          return conn.Table<Person>().ToList();
       }
       catch (Exception ex)
       {
          StatusMessage = string.Format("Failed to retrieve data. {0}", ex.Message);
       }
    
       return new List<Person>();
    }
    
  6. Guarde el archivo PersonRepository.cs.

Integración del repositorio en la interfaz de usuario

  1. Abra el archivo MauiProgram.cs.

  2. En la función CreateMauiApp, después de las instrucciones que agregan la página MainPage como servicio singleton a la aplicación, agregue código para realizar las siguientes tareas:

    • Crear una variable de cadena denominada dbPath. Inicializar esta cadena con la expresión FileAccessHelper.GetLocalFilePath("people.db3"). El archivo de base de datos que usa la aplicación se denomina people.db3, y la aplicación guarda este archivo en el almacenamiento local en el dispositivo.

    • Usar la inserción de dependencias para agregar la clase PersonRepository como servicio singleton a la aplicación. La clase PersonRepository expone un constructor que toma la ruta de acceso al archivo de base de datos como un parámetro de cadena.

    El código completado de la función CreateMauiApp debería tener el siguiente aspecto:

    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
            });
    
        // Add this code
        string dbPath = FileAccessHelper.GetLocalFilePath("people.db3");
        builder.Services.AddSingleton<PersonRepository>(s => ActivatorUtilities.CreateInstance<PersonRepository>(s, dbPath));
    
        return builder.Build();
    }
    
  3. Guarde el archivo MauiProgram.cs.

  4. Expanda App.xaml en el Explorador de soluciones y abra el archivo App.xaml.cs.

  5. Agregue un public, propiedad static denominada PersonRepo. Esta propiedad contiene un objeto PersonRepository a la clase App.

  6. Inicialice la propiedad PersonRepo en el constructor agregando un parámetro PersonRepository al constructor y estableciendo la propiedad 'PersonRepo' en el valor de este parámetro. Este es el aspecto que debería tener la clase App completada:

    public partial class App : Application
    {
        public static PersonRepository PersonRepo { get; private set; }
    
        public App(PersonRepository repo)
        {
            InitializeComponent();
            PersonRepo = repo;
        }
    }
    

Nota:

El proceso de inserción de dependencias rellena automáticamente el parámetro repo en el constructor.

Prueba de la aplicación

  1. Compile la solución mediante CTRL+Mayús+B.

  2. Una vez completada la compilación, inicie la depuración mediante F5. Cuando aparezca la interfaz de usuario, escriba su nombre y seleccione Agregar persona.

    Recorte de pantalla de la aplicación con un mensaje correcto que indica que se agrega un registro.

  3. Seleccione Obtener todas las personas y compruebe que aparezca su nombre.

    Captura de pantalla de la aplicación con una lista de todos los registros de la base de datos.

  4. Experimente agregando más nombres y recuperando la lista de personas almacenadas.

  5. Vuelva a Visual Studio o Visual Studio Code y detenga la depuración mediante Mayús+F5.

  6. Reinicie la aplicación y seleccione Obtener todas las personas. Compruebe que los nombres almacenados anteriormente todavía estén almacenados en la base de datos. Cierre la aplicación cuando haya terminado.