Lokalne bazy danych programu .NET MAUI
Aparat bazy danych SQLite umożliwia aplikacjom interfejsu użytkownika aplikacji wieloplatformowych platformy .NET (.NET MAUI) ładowanie i zapisywanie obiektów danych w kodzie udostępnionym. Możesz zintegrować SQLite.NET z aplikacjami .NET MAUI, aby przechowywać i pobierać informacje w lokalnej bazie danych, wykonując następujące kroki:
- Zainstaluj pakiet NuGet.
- Konfigurowanie stałych.
- Utwórz klasę dostępu do bazy danych.
- Uzyskiwanie dostępu do danych.
- Konfiguracja zaawansowana.
W tym artykule użyto pakietu NuGet sqlite-net-pcl w celu zapewnienia dostępu bazy danych SQLite do tabeli do przechowywania zadań do wykonania. Alternatywą jest użycie pakietu NuGet Microsoft.Data.Sqlite , który jest uproszczonym dostawcą ADO.NET dla biblioteki SQLite. Microsoft.Data.Sqlite implementuje typowe abstrakcje ADO.NET dla funkcji, takich jak połączenia, polecenia i czytniki danych.
Instalowanie pakietu NuGet SQLite
Użyj menedżera pakietów NuGet, aby wyszukać pakiet sqlite-net-pcl i dodać najnowszą wersję do projektu aplikacji .NET MAUI.
Istnieje kilka pakietów NuGet o podobnych nazwach. Poprawny pakiet ma następujące atrybuty:
- Identyfikator: sqlite-net-pcl
- Autorzy: SQLite-net
- Właściciele: praeclarum
- Link NuGet: sqlite-net-pcl
Pomimo nazwy pakietu użyj pakietu NuGet sqlite-net-pcl w projektach .NET MAUI.
Ważne
SQLite.NET to biblioteka innej firmy obsługiwana przez repozytorium praeclarum/sqlite-net.
Instalowanie SQLitePCLRaw.bundle_green
Oprócz sqlite-net-pcl tymczasowo należy zainstalować podstawową zależność, która uwidacznia sqlite na każdej platformie:
- Identyfikator: SQLitePCLRaw.bundle_green
- Wersja:>= 2.1.0
- Autorzy: Eric Sink
- Właściciele: Eric Sink
- Link narzędzia NuGet: SQLitePCLRaw.bundle_green
Konfigurowanie stałych aplikacji
Dane konfiguracji, takie jak nazwa pliku bazy danych i ścieżka, mogą być przechowywane jako stałe w aplikacji. Przykładowy projekt zawiera plik Constants.cs zawierający typowe dane konfiguracji:
public static class Constants
{
public const string DatabaseFilename = "TodoSQLite.db3";
public const SQLite.SQLiteOpenFlags Flags =
// open the database in read/write mode
SQLite.SQLiteOpenFlags.ReadWrite |
// create the database if it doesn't exist
SQLite.SQLiteOpenFlags.Create |
// enable multi-threaded database access
SQLite.SQLiteOpenFlags.SharedCache;
public static string DatabasePath =>
Path.Combine(FileSystem.AppDataDirectory, DatabaseFilename);
}
W tym przykładzie plik stałych określa domyślne SQLiteOpenFlag
wartości wyliczenia, które są używane do inicjowania połączenia z bazą danych. Wyliczenie SQLiteOpenFlag
obsługuje następujące wartości:
Create
: Połączenie automatycznie utworzy plik bazy danych, jeśli nie istnieje.FullMutex
: Połączenie jest otwierane w trybie serializacji wątków.NoMutex
: Połączenie jest otwierane w trybie wielowątkowy.PrivateCache
: Połączenie nie będzie uczestniczyć w udostępnionej pamięci podręcznej, nawet jeśli jest włączone.ReadWrite
: Połączenie może odczytywać i zapisywać dane.SharedCache
: Połączenie będzie uczestniczyć w udostępnionej pamięci podręcznej, jeśli jest włączone.ProtectionComplete
: plik jest zaszyfrowany i niedostępny, gdy urządzenie jest zablokowane.ProtectionCompleteUnlessOpen
: plik jest szyfrowany, dopóki nie zostanie otwarty, ale będzie dostępny nawet wtedy, gdy użytkownik zablokuje urządzenie.ProtectionCompleteUntilFirstUserAuthentication
: plik jest szyfrowany do momentu uruchomienia i odblokowania urządzenia przez użytkownika.ProtectionNone
: plik bazy danych nie jest zaszyfrowany.
Może być konieczne określenie różnych flag w zależności od sposobu użycia bazy danych. Aby uzyskać więcej informacji na temat SQLiteOpenFlags
programu , zobacz Otwieranie nowego połączenia z bazą danych na sqlite.org.
Tworzenie klasy dostępu do bazy danych
Klasa otoki bazy danych abstrakcji warstwy dostępu do danych z pozostałej części aplikacji. Ta klasa centralizuje logikę zapytań i upraszcza zarządzanie inicjowaniem bazy danych, co ułatwia refaktoryzowanie lub rozszerzanie operacji na danych w miarę rozwoju aplikacji. Przykładowa aplikacja definiuje klasę TodoItemDatabase
w tym celu.
Inicjowanie z opóźnieniem
Metoda TodoItemDatabase
używa asynchronicznej leniwej inicjalizacji w celu opóźnienia inicjowania bazy danych do momentu pierwszego uzyskania do niej dostępu z prostą Init
metodą wywoływaną przez każdą metodę w klasie:
public class TodoItemDatabase
{
SQLiteAsyncConnection Database;
public TodoItemDatabase()
{
}
async Task Init()
{
if (Database is not null)
return;
Database = new SQLiteAsyncConnection(Constants.DatabasePath, Constants.Flags);
var result = await Database.CreateTableAsync<TodoItem>();
}
...
}
Metody manipulowania danymi
Klasa TodoItemDatabase
zawiera metody dla czterech typów manipulowania danymi: tworzenie, odczytywanie, edytowanie i usuwanie. Biblioteka SQLite.NET udostępnia prostą relacyjną mapę obiektów (ORM), która umożliwia przechowywanie i pobieranie obiektów bez konieczności pisania instrukcji SQL.
W poniższym przykładzie przedstawiono metody manipulowania danymi w przykładowej aplikacji:
public class TodoItemDatabase
{
...
public async Task<List<TodoItem>> GetItemsAsync()
{
await Init();
return await Database.Table<TodoItem>().ToListAsync();
}
public async Task<List<TodoItem>> GetItemsNotDoneAsync()
{
await Init();
return await Database.Table<TodoItem>().Where(t => t.Done).ToListAsync();
// SQL queries are also possible
//return await Database.QueryAsync<TodoItem>("SELECT * FROM [TodoItem] WHERE [Done] = 0");
}
public async Task<TodoItem> GetItemAsync(int id)
{
await Init();
return await Database.Table<TodoItem>().Where(i => i.ID == id).FirstOrDefaultAsync();
}
public async Task<int> SaveItemAsync(TodoItem item)
{
await Init();
if (item.ID != 0)
return await Database.UpdateAsync(item);
else
return await Database.InsertAsync(item);
}
public async Task<int> DeleteItemAsync(TodoItem item)
{
await Init();
return await Database.DeleteAsync(item);
}
}
Uzyskiwanie dostępu do danych
Klasę TodoItemDatabase
można zarejestrować jako pojedynczą, która może być używana w całej aplikacji, jeśli używasz iniekcji zależności. Możesz na przykład zarejestrować strony i klasę dostępu bazy danych jako usługi w IServiceCollection
obiekcie w MauiProgram.cs za pomocą AddSingleton
metod i AddTransient
:
builder.Services.AddSingleton<TodoListPage>();
builder.Services.AddTransient<TodoItemPage>();
builder.Services.AddSingleton<TodoItemDatabase>();
Te usługi można następnie automatycznie wprowadzać do konstruktorów klas i uzyskiwać do nich dostęp:
TodoItemDatabase database;
public TodoItemPage(TodoItemDatabase todoItemDatabase)
{
InitializeComponent();
database = todoItemDatabase;
}
async void OnSaveClicked(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(Item.Name))
{
await DisplayAlert("Name Required", "Please enter a name for the todo item.", "OK");
return;
}
await database.SaveItemAsync(Item);
await Shell.Current.GoToAsync("..");
}
Alternatywnie można utworzyć nowe wystąpienia klasy dostępu bazy danych:
TodoItemDatabase database;
public TodoItemPage()
{
InitializeComponent();
database = new TodoItemDatabase();
}
Aby uzyskać więcej informacji na temat wstrzykiwania zależności w aplikacjach .NET MAUI, zobacz Wstrzykiwanie zależności.
Konfiguracja zaawansowana
SqLite udostępnia niezawodny interfejs API z większą ilością funkcji, niż opisano w tym artykule i przykładowej aplikacji. W poniższych sekcjach opisano funkcje, które są ważne dla skalowalności.
Aby uzyskać więcej informacji, zobacz dokumentację sqlite dotyczącą sqlite.org.
Rejestrowanie z wyprzedzeniem zapisu
Domyślnie sqLite używa tradycyjnego dziennika wycofywania. Kopia niezmienionej zawartości bazy danych jest zapisywana w osobnym pliku wycofywania, a następnie zmiany są zapisywane bezpośrednio w pliku bazy danych. Zatwierdzenie występuje po usunięciu dziennika wycofywania.
Funkcja write-Ahead Logging (WAL) zapisuje zmiany w osobnym pliku WAL najpierw. W trybie WAL zatwierdzenie jest specjalnym rekordem dołączonym do pliku WAL, który umożliwia wykonywanie wielu transakcji w jednym pliku WAL. Plik WAL jest scalony z powrotem do pliku bazy danych w specjalnej operacji nazywanej punktem kontrolnym.
Funkcja WAL może być szybsza w przypadku lokalnych baz danych, ponieważ czytelnicy i autorzy nie blokują się nawzajem, co pozwala na współbieżne operacje odczytu i zapisu. Jednak tryb WAL nie zezwala na zmiany rozmiaru strony, dodaje dodatkowe skojarzenia plików do bazy danych i dodaje dodatkową operację tworzenia punktów kontrolnych.
Aby włączyć funkcję WAL w SQLite.NET, wywołaj metodę EnableWriteAheadLoggingAsync
w wystąpieniu SQLiteAsyncConnection
:
await Database.EnableWriteAheadLoggingAsync();
Aby uzyskać więcej informacji, zobacz SQLite Write-Ahead Logging on sqlite.org (Rejestrowanie przed zapisem sqlite na sqlite.org).
Kopiowanie bazy danych
Istnieje kilka przypadków, w których może być konieczne skopiowanie bazy danych SQLite:
- Baza danych została dostarczona z aplikacją, ale musi zostać skopiowana lub przeniesiona do magazynu zapisywalnego na urządzeniu przenośnym.
- Należy utworzyć kopię zapasową lub kopię bazy danych.
- Musisz wersję, przenieść lub zmienić nazwę pliku bazy danych.
Ogólnie rzecz biorąc, przenoszenie, zmienianie nazwy lub kopiowanie pliku bazy danych jest tym samym procesem co każdy inny typ pliku z kilkoma dodatkowymi zagadnieniami:
- Przed podjęciem próby przeniesienia pliku bazy danych należy zamknąć wszystkie połączenia bazy danych.
- Jeśli używasz funkcji Write-Ahead Logging, narzędzie SQLite utworzy plik dostępu do pamięci udostępnionej (shm) i plik (Write Ahead Log) (wal). Upewnij się, że zastosowano również wszelkie zmiany w tych plikach.