.NET MAUI 로컬 데이터베이스

Browse sample. 샘플 찾아보기

SQLite 데이터베이스 엔진을 사용하면 .NET 다중 플랫폼 앱 UI(.NET MAUI) 앱이 데이터 개체를 로드하고 공유 코드에 저장할 수 있습니다. 다음 단계에 따라 SQLite.NET .NET MAUI 앱에 통합하여 로컬 데이터베이스에 정보를 저장하고 검색할 수 있습니다.

  1. NuGet 패키지를 설치합니다.
  2. 상수 구성
  3. 데이터베이스 액세스 클래스를 만듭니다.
  4. 데이터에 액세스합니다.
  5. 고급 구성

이 문서에서는 sqlite-net-pcl NuGet 패키지를 사용하여 할 일 항목을 저장할 테이블에 대한 SQLite 데이터베이스 액세스를 제공합니다. 대안은 SQLite용 경량 ADO.NET 공급자인 Microsoft.Data.Sqlite NuGet 패키지를 사용하는 것입니다. Microsoft.Data.Sqlite는 연결, 명령 및 데이터 판독기와 같은 기능에 대한 일반적인 ADO.NET 추상화 기능을 구현합니다.

SQLite NuGet 패키지 설치

NuGet 패키지 관리자를 사용하여 sqlite-net-pcl 패키지를 검색하고 최신 버전을 .NET MAUI 앱 프로젝트에 추가합니다.

이름이 유사한 NuGet 패키지가 여러 개 있습니다. 올바른 패키지에는 이러한 특성이 있습니다.

  • ID: sqlite-net-pcl
  • 작성자: SQLite-net
  • 소유자: praeclarum
  • NuGet 링크:sqlite-net-pcl

패키지 이름에도 불구하고 .NET MAUI 프로젝트에서 sqlite-net-pcl NuGet 패키지를 사용합니다.

Important

SQLite.NET praeclarum/sqlite-net 리포지토리에서 지원되는 타사 라이브러리입니다.

설치 SQLitePCLRaw.bundle_green

sqlite-net-pcl 외에도 각 플랫폼에 SQLite를 노출하는 기본 종속성을 일시적으로 설치해야 합니다.

  • ID: SQLitePCLRaw.bundle_green
  • 버전:>= 2.1.0
  • 저자: 에릭 싱크
  • 소유자: Eric Sink
  • NuGet 링크:SQLitePCLRaw.bundle_green

앱 상수 구성

데이터베이스 파일 이름 및 경로와 같은 구성 데이터는 앱에 상수로 저장할 수 있습니다. 샘플 프로젝트에는 일반적인 구성 데이터를 제공하는 Constants.cs 파일이 포함되어 있습니다.

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

이 예제에서 상수 파일은 데이터베이스 연결을 초기화하는 데 사용되는 기본 SQLiteOpenFlag 열거형 값을 지정합니다. 열거형은 SQLiteOpenFlag 다음 값을 지원합니다.

  • Create: 연결이 없는 경우 자동으로 데이터베이스 파일을 만듭니다.
  • FullMutex: 연결이 serialize된 스레딩 모드로 열립니다.
  • NoMutex: 연결이 다중 스레딩 모드로 열립니다.
  • PrivateCache: 연결이 설정된 경우에도 공유 캐시에 참여하지 않습니다.
  • ReadWrite: 연결에서 데이터를 읽고 쓸 수 있습니다.
  • SharedCache: 연결이 활성화된 경우 공유 캐시에 참여합니다.
  • ProtectionComplete: 디바이스가 잠겨 있는 동안 파일이 암호화되고 액세스할 수 없습니다.
  • ProtectionCompleteUnlessOpen: 파일이 열릴 때까지 암호화되지만 사용자가 디바이스를 잠그더라도 액세스할 수 있습니다.
  • ProtectionCompleteUntilFirstUserAuthentication: 사용자가 디바이스를 부팅하고 잠금을 해제할 때까지 파일이 암호화됩니다.
  • ProtectionNone: 데이터베이스 파일이 암호화되지 않았습니다.

데이터베이스 사용 방법에 따라 다른 플래그를 지정해야 할 수 있습니다. 자세한 내용은 SQLiteOpenFlagssqlite.org 새 데이터베이스 커넥트 열기를 참조하세요.

데이터베이스 액세스 클래스 만들기

데이터베이스 래퍼 클래스는 앱의 나머지 부분의 데이터 액세스 계층을 추상화합니다. 이 클래스는 쿼리 논리를 중앙 집중화하고 데이터베이스 초기화 관리를 간소화하므로 앱이 증가함에 따라 데이터 작업을 보다 쉽게 리팩터링하거나 확장할 수 있습니다. 샘플 앱은 이 용도에 대한 클래스를 TodoItemDatabase 정의합니다.

지연 초기화

TodoItemDatabase 동기 지연 초기화를 사용하여 클래스의 각 메서드에서 호출되는 간단한 Init 메서드를 사용하여 데이터베이스가 처음 액세스할 때까지 데이터베이스 초기화를 지연합니다.

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

데이터 조작 메서드

클래스에는 TodoItemDatabase 만들기, 읽기, 편집 및 삭제의 네 가지 데이터 조작 형식에 대한 메서드가 포함됩니다. SQLite.NET 라이브러리는 SQL 문을 작성하지 않고 개체를 저장하고 검색할 수 있는 간단한 ORM(개체 관계형 맵)을 제공합니다.

다음 예제에서는 샘플 앱의 데이터 조작 메서드를 보여 줍니다.

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

데이터 액세스

TodoItemDatabase 종속성 주입을 사용하는 경우 앱 전체에서 사용할 수 있는 싱글톤으로 클래스를 등록할 수 있습니다. 예를 들어 페이지 및 데이터베이스 액세스 클래스를 MauiProgram.cs의 개체에 서비스 IServiceCollectionAddSingleton 등록할 수 있습니다AddTransient.

builder.Services.AddSingleton<TodoListPage>();
builder.Services.AddTransient<TodoItemPage>();

builder.Services.AddSingleton<TodoItemDatabase>();

그런 다음, 이러한 서비스를 클래스 생성자에 자동으로 삽입하고 액세스할 수 있습니다.

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

또는 데이터베이스 액세스 클래스의 새 인스턴스를 만들 수 있습니다.

TodoItemDatabase database;

public TodoItemPage()
{
    InitializeComponent();
    database = new TodoItemDatabase();
}

.NET MAUI 앱의 종속성 주입에 대한 자세한 내용은 종속성 주입을 참조하세요.

고급 구성

SQLite는 이 문서 및 샘플 앱에서 다루는 것보다 더 많은 기능을 갖춘 강력한 API를 제공합니다. 다음 섹션에서는 확장성에 중요한 기능을 다룹니다.

자세한 내용은 sqlite.org 대한 SQLite 설명서를 참조하세요.

미리 쓰기 로깅

기본적으로 SQLite는 기존 롤백 저널을 사용합니다. 변경되지 않은 데이터베이스 콘텐츠의 복사본은 별도의 롤백 파일에 기록된 다음 변경 내용이 데이터베이스 파일에 직접 기록됩니다. COMMIT은 롤백 저널이 삭제될 때 발생합니다.

WAL(Write-Ahead Logging)은 먼저 변경 내용을 별도의 WAL 파일에 씁니다. WAL 모드에서 COMMIT은 WAL 파일에 추가되는 특수 레코드로, 단일 WAL 파일에서 여러 트랜잭션이 발생할 수 있습니다. WAL 파일은 검사point라는 특수 작업에서 데이터베이스 파일로 다시 병합됩니다.

읽기 권한자와 작성기가 서로를 차단하지 않으므로 읽기 및 쓰기 작업을 동시에 수행할 수 있으므로 로컬 데이터베이스의 경우 WAL이 더 빠를 수 있습니다. 그러나 WAL 모드는 페이지 크기를 변경할 수 없으며 데이터베이스에 파일 연결을 추가하고 추가 검사 점 지정 작업을 추가합니다.

SQLite.NET WAL을 사용하도록 설정하려면 인스턴스에서 EnableWriteAheadLoggingAsync 메서드를 SQLiteAsyncConnection 호출합니다.

await Database.EnableWriteAheadLoggingAsync();

자세한 내용은 sqlite.org SQLite 미리 쓰기 로깅 을 참조하세요.

데이터베이스 복사

SQLite 데이터베이스를 복사해야 하는 몇 가지 경우가 있습니다.

  • 데이터베이스가 애플리케이션과 함께 제공되었지만 모바일 디바이스의 쓰기 가능한 스토리지로 복사하거나 이동해야 합니다.
  • 데이터베이스의 백업 또는 복사본을 만들어야 합니다.
  • 데이터베이스 파일의 버전 관리, 이동 또는 이름을 바꿔야 합니다.

일반적으로 데이터베이스 파일 이동, 이름 바꾸기 또는 복사는 몇 가지 추가 고려 사항이 있는 다른 파일 형식과 동일한 프로세스입니다.

  • 데이터베이스 파일을 이동하기 전에 모든 데이터베이스 연결 닫아야 합니다.
  • 미리 쓰기 로깅을 사용하는 경우 SQLite는 공유 메모리 액세스(.shm) 파일 및 (미리 쓰기 로그)(.wal) 파일을 만듭니다. 이러한 파일에도 변경 내용을 적용해야 합니다.