Esercizio - Archiviare i dati in locale con SQLite

Completato

In questo esercizio, si usa SQLite per archiviare le informazioni in locale con un'applicazione. Nello scenario di esempio è stato deciso di memorizzare nella cache i dati per l'app di social media per migliorare i tempi di risposta. In questo esercizio viene creato e utilizzato un database SQLite locale per l'archiviazione di informazioni sulle persone. Il file di database fisico viene salvato nell'archiviazione locale.

Questo modulo usa .NET 9.0 SDK. Assicurarsi di avere installato .NET 9.0 eseguendo il comando seguente nel terminale dei comandi preferito:

dotnet --list-sdks

Verrà visualizzato un output simile all'esempio seguente:

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

Assicurarsi che sia elencata una versione che inizia con 9. Se il comando non è presente nell'elenco o non viene trovato, installare la versione più recente di .NET 9.0 SDK.

Aprire la soluzione iniziale

  1. Clonare o scaricare il repository dell'esercizio.

    Nota

    È consigliabile clonare o scaricare il contenuto dell'esercizio in un percorso di cartella breve, ad esempio C:\dev, per evitare che i file generati dalla compilazione superino la lunghezza massima del percorso.

  2. Usare Visual Studio per aprire la soluzione People.sln, disponibile in mslearn-dotnetmaui-store-local-data>People o nella cartella starter in Visual Studio Code.

    Nota

    Non provare ancora a eseguire l'applicazione, il codice è incompleto e genererà eccezioni finché non si aggiungeranno gli elementi mancanti più avanti in questo esercizio.

Definire un'entità SQLite

  1. Aprire il file Person.cs nella cartella Modelli.

  2. Aggiungere una proprietà int denominata Id alla classe Person.

  3. Aggiungere una proprietà string denominata Name. La classe dovrebbe risultare simile alla seguente:

    namespace People.Models;
    
    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    
  4. Salvare il file Person.cs.

Aggiungere la libreria SQLite

  1. Fare clic con il pulsante destro del mouse sul nodo del progetto People in Esplora soluzioni in Visual Studio.

  2. Nel menu di scelta rapida visualizzato selezionare Gestisci pacchetti NuGet.

  3. Cercare e selezionare sqlite-net-pcl, quindi selezionare Installa.

    Screenshot che mostra Gestione pacchetti NuGet con la libreria sqlite-net-pcl selezionata.

Se si usa Visual Studio Code, aprire il terminale e questi pacchetti con i comandi seguenti:

dotnet add package sqlite-net-pcl

Aggiungere attributi SQLite

  1. Nel file Person.cs aggiungere una direttiva using per lo spazio dei nomi SQLite al file per la classe Person. Questa direttiva consente di usare gli attributi SQLite.

    using SQLite;
    
    namespace People.Models;
    
    public class Person
    {
        ...
    }
    
  2. Annotare la classe Person con l'attributo [Table] e specificare il nome della tabella come people.

  3. Specificare la proprietà Id come chiave primaria. Annotarlo con gli attributi [PrimaryKey] e [AutoIncrement].

  4. Aggiungere annotazioni alla proprietà Name. Specificare il valore MaxLength come 250. Specificare che ogni valore nella colonna deve essere Unique.

    La classe completata avrà l'aspetto seguente:

    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. Salvare il file Person.cs.

Stabilire la connessione al database

  1. Aprire il file PersonRepository.cs.

  2. Esaminare la classe PersonRepository. Questa classe contiene codice di base incompleto con marcatori TODO in cui si aggiunge la funzionalità per accedere al database.

  3. Aggiungere una direttiva using per gli spazi dei nomi SQLite e People.Models al file per la classe PersonRepository.cs.

  4. Aggiungere un campo privato SQLiteConnection denominato conn alla classe sopra la funzione Init.

  5. Nella funzione Init verificare che conn non sia uguale a null. In tal caso, l'esecuzione è immediata.

    if (conn != null)
        return;
    

    In questo modo il codice di inizializzazione per il database SQLite viene eseguito una sola volta.

  6. Inizializzare il campo conn per connettersi al database usando la variabile _dbPath.

  7. Utilizzare il metodo conn.CreateTable per creare una tabella per archiviare i dati Person. La funzione Init completata avrà l'aspetto seguente:

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

Inserire una riga nel database

  1. Nella classe PersonRepository cercare il metodo AddNewPerson.

  2. Per inserire un nuovo oggetto Person, sostituire il commento TODO in questo metodo con il codice. Il codice chiama prima di tutto Init per verificare che il database sia inizializzato, quindi usa il metodo SQLiteConnection dell'oggetto Insert ù. Impostare la variabile result sul valore restituito dal metodo Insert, come illustrato nel codice seguente:

    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 });
            ...
        }
        ...
    }
    

Recuperare righe dal database

  1. Nella classe PersonRepository cercare il metodo GetAllPeople.

  2. Chiamare Init per verificare che il database sia inizializzato.

  3. Utilizzare il metodo Table\<T> generico per recuperare tutte le righe della tabella. Specificare Person come parametro di tipo.

  4. Utilizzare il metodo di estensione ToList() per trasformare il risultato in una raccolta List\<Person> e restituire questa raccolta.

  5. Aggiungere la gestione degli errori eseguendo il wrapping del codice in un blocco try-catch. Se si verifica un errore, impostare la proprietà StatusMessage sulla proprietà dell'eccezione Message e restituire un insieme vuoto. Il metodo completo dovrebbe essere simile al seguente:

    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. Aprire il file PersonRepository.cs.

Integrare il repository nell'interfaccia utente

  1. Aprire il file MauiProgram.cs.

  2. Nella funzione CreateMauiApp, dopo le istruzioni che aggiungono la pagina MainPage come servizio singleton all'app, aggiungere il codice per eseguire le seguenti attività:

    • Creare una variabile stringa denominata dbPath. Inizializzare questa stringa con l'espressione FileAccessHelper.GetLocalFilePath("people.db3"). Il file di database usato dall'app viene chiamato people.db3 e l'app lo salva nell'archiviazione locale sul dispositivo.

    • Utilizzare l'inserimento di dipendenze per aggiungere la classe PersonRepository come servizio singleton all'app. La classe PersonRepository espone un costruttore che accetta il percorso del file di database come parametro stringa.

    Il codice completato per la funzione CreateMauiApp avrà il seguente aspetto:

    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. Salvare il file MauiProgram.cs.

  4. Espandere App.xaml in Esplora soluzioni e quindi aprire il file App.xaml.cs.

  5. Aggiungere una proprietà public, static denominata PersonRepo. Questa proprietà contiene un oggetto PersonRepository per la classe App.

  6. Inizializzare la proprietà PersonRepo nel costruttore aggiungendo un parametro PersonRepository al costruttore e impostando la proprietà “PersonRepo” sul valore in questo parametro. La classe App completata avrà il seguente aspetto:

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

Nota

Il processo di inserimento delle dipendenze popola automaticamente il parametro repo nel costruttore.

Testare l'applicazione

  1. Premere CTRL+MAIUSC+B per compilare la soluzione.

  2. Al termine della compilazione, avviare il debug usando F5. Quando viene visualizzata l'interfaccia utente, immettere il proprio nome e selezionare Aggiungi persona.

    Screenshot dell'app con un messaggio di operazione riuscita che indica che è stato aggiunto un record.

  3. Selezionare Ottieni tutte le persone e verificare che venga visualizzato il proprio nome.

    Screenshot dell'app con un elenco di tutti i record nel database.

  4. Provare ad aggiungere altri nomi e recuperare l'elenco di persone archiviate.

  5. Tornare a Visual Studio o Visual Studio Code e arrestare il debug usando MAIUSC+F5.

  6. Riavviare l'app e selezionare Ottieni tutte le persone. Verificare che i nomi archiviati in precedenza siano ancora archiviati nel database. Al termine, chiudere l'app.