Esercizio - Usare SQLite in modo asincrono

Completato

L'applicazione funziona bene, ma se il database contiene molte righe l'interfaccia utente può smettere di rispondere mentre l'app esegue query e altre operazioni sul database. In questo esercizio si convertirà l'applicazione dall'API SQLite sincrona alla versione asincrona. In questo modo, l'applicazione rimarrà sempre reattiva, indipendentemente dal numero di query eseguite nel database.

Creare una connessione asincrona

  1. Aprire il file PersonRepository.cs nel progetto People.

  2. Modificare la definizione del metodo Init in modo che sia async. Cambiare il tipo restituito del metodo in Task.

  3. Modificare la proprietà conn in un SQLiteAsyncConnection e aggiornare il codice nel metodo Init che inizializza la connessione.

  4. Sostituire la chiamata al metodo sincrono CreateTable con il metodo asincrono CreateTableAsync.

    Il codice completato avrà l'aspetto seguente:

    private SQLiteAsyncConnection conn;
    
    private async Task Init()
    {
        if (conn != null)
            return;
    
        conn = new SQLiteAsyncConnection(_dbPath);
    
        await conn.CreateTableAsync<Person>();
    }
    

Inserire un elemento in una tabella in modo asincrono

  1. Modificare la definizione del metodo AddNewPerson in modo che sia async. Cambiare il tipo restituito del metodo in Task.

  2. Aggiungere la parola chiave await alla chiamata al metodo Init perché Init è ora un metodo async.

  3. Aggiornare il metodo AddNewPerson per inserire una nuova Person usando un'operazione di inserimento asincrona.

    Il codice dovrebbe essere simile al seguente:

    using System.Threading.Tasks;
    ...
    public async Task AddNewPerson(string name)
    {
       int result = 0;
       try
       {
          // Call Init()
          await Init();
    
          // basic validation to ensure a name was entered
          if (string.IsNullOrEmpty(name))
                throw new Exception("Valid name required");
    
          result = await conn.InsertAsync(new Person { Name = name });
    
          StatusMessage = string.Format("{0} record(s) added [Name: {1})", result, name);
       }
       catch (Exception ex)
       {
          StatusMessage = string.Format("Failed to add {0}. Error: {1}", name, ex.Message);
       }
    }
    

Ottenere tutti gli elementi da una tabella in modo asincrono

  1. Modificare la definizione del metodo GetAllPeople. Questo metodo deve essere async e restituire un oggetto Task<List<Person>>.

  2. Aggiungere la parola chiave await alla chiamata al metodo Init.

  3. Aggiornare il metodo in modo che restituisca i risultati usando una chiamata asincrona.

    Il codice dovrebbe essere simile al seguente:

    public async Task<List<Person>> GetAllPeople()
    {
       try
       {
          await Init();
          return await conn.Table<Person>().ToListAsync();
       }
       catch (Exception ex)
       {
          StatusMessage = string.Format("Failed to retrieve data. {0}", ex.Message);
       }
    
       return new List<Person>();
    }
    
  4. Salvare il file PersonRepository.cs.

Testare la funzionalità asincrona

  1. Espandere MainPage.xaml in Esplora soluzioni e aprire il file MainPage.xaml.cs.

  2. Modificare entrambi i gestori eventi button-click per usare i metodi asincroni della classe PersonRepository. Usare le parole chiave async e await:

      public async void OnNewButtonClicked(object sender, EventArgs args)
      {
         statusMessage.Text = "";
    
         await App.PersonRepo.AddNewPerson(newPerson.Text);
         statusMessage.Text = App.PersonRepo.StatusMessage;
      }
    
      public async void OnGetButtonClicked(object sender, EventArgs args)
      {
         statusMessage.Text = "";
    
         List<Person> people = await App.PersonRepo.GetAllPeople();
         peopleList.ItemsSource = people;
      }
    
  3. Salvare il file MainPage.xaml.cs.

  4. Compilare ed eseguire il programma su Windows e Android per verificare che funzioni ancora come prima.