All skills
davidortinau avatar

/maui-sqlite-database

@74acbe3

Add SQLite local database storage to .NET MAUI apps using sqlite-net-pcl. Covers data models with ORM attributes, async database service with lazy init, DI registration, WAL mode, and file management. Works with any UI pattern (XAML/MVVM, C# Markup, MauiReactor). USE FOR: "SQLite database", "local database", "sqlite-net-pcl", "offline storage", "CRUD database", "database service", "WAL mode", "CreateTableAsync", "local data persistence", "ORM attributes". DO NOT USE FOR: REST API data fetching (use maui-rest-api), secure credential storage (use maui-secure-storage), or file picking (use maui-file-handling).

Use this Skill: https://skilld.dev/gh/davidortinau/maui-skills/maui-sqlite-database

This session only. Nothing lands on disk.

referencessqlite-database-api.md

≈1.2k tokens on demand. Your agent reads this file only when SKILL.md points to it.

SQLite Database API Reference

NuGet Package

Install sqlite-net-pcl by praeclarum:

<PackageReference Include="sqlite-net-pcl" Version="1.9.*" />
<PackageReference Include="SQLitePCLRaw.bundle_green" Version="2.1.*" />

Constants Class

public static class Constants
{
    public const string DatabaseFilename = "app.db3";

    public const SQLite.SQLiteOpenFlags Flags =
        SQLite.SQLiteOpenFlags.ReadWrite |
        SQLite.SQLiteOpenFlags.Create |
        SQLite.SQLiteOpenFlags.SharedCache;

    public static string DatabasePath =>
        Path.Combine(FileSystem.AppDataDirectory, DatabaseFilename);
}
  • ReadWrite | Create | SharedCache — standard flags for mobile apps.
  • Use FileSystem.AppDataDirectory (not Environment.GetFolderPath) for cross-platform correctness on all MAUI targets.

Data Model

using SQLite;

public class TodoItem
{
    [PrimaryKey, AutoIncrement]
    public int Id { get; set; }

    [MaxLength(250)]
    public string Name { get; set; } = string.Empty;

    public bool Done { get; set; }
}

ORM Attributes

Key attributes: [PrimaryKey], [AutoIncrement], [MaxLength(n)], [Indexed], [Ignore], [Column("name")], [Unique], [NotNull], [Table("name")].


Database Service

Use the lazy async initialization pattern — the connection is created once, on first access, and all callers await the same instance:

using SQLite;

public class DatabaseService
{
    private SQLiteAsyncConnection? _database;

    private async Task<SQLiteAsyncConnection> GetDatabaseAsync()
    {
        if (_database is not null)
            return _database;

        _database = new SQLiteAsyncConnection(Constants.DatabasePath, Constants.Flags);
        await _database.ExecuteAsync("PRAGMA journal_mode=WAL;");
        await _database.CreateTableAsync<TodoItem>();
        return _database;
    }

    public async Task<List<TodoItem>> GetItemsAsync()
    {
        var db = await GetDatabaseAsync();
        return await db.Table<TodoItem>().ToListAsync();
    }

    public async Task<List<TodoItem>> GetItemsAsync(bool done)
    {
        var db = await GetDatabaseAsync();
        return await db.Table<TodoItem>().Where(i => i.Done == done).ToListAsync();
    }

    public async Task<TodoItem?> GetItemAsync(int id)
    {
        var db = await GetDatabaseAsync();
        return await db.Table<TodoItem>().Where(i => i.Id == id).FirstOrDefaultAsync();
    }

    public async Task<int> SaveItemAsync(TodoItem item)
    {
        var db = await GetDatabaseAsync();
        return item.Id != 0
            ? await db.UpdateAsync(item)
            : await db.InsertAsync(item);
    }

    public async Task<int> DeleteItemAsync(TodoItem item)
    {
        var db = await GetDatabaseAsync();
        return await db.DeleteAsync(item);
    }

    public async Task CloseConnectionAsync()
    {
        if (_database is not null)
        {
            await _database.CloseAsync();
            _database = null;
        }
    }
}

DI Registration

Register as a singleton in MauiProgram.cs:

builder.Services.AddSingleton<DatabaseService>();

Inject into view models or pages:

public class TodoListViewModel(DatabaseService database)
{
    private readonly DatabaseService _database = database;
}

WAL (Write-Ahead Logging)

Enabled in GetDatabaseAsync() via PRAGMA journal_mode=WAL;.

  • Readers do not block writers and vice versa.
  • Better performance for concurrent read/write workloads.
  • Recommended for all MAUI apps.

Database File Management

// Delete database
await databaseService.CloseConnectionAsync();
if (File.Exists(Constants.DatabasePath))
    File.Delete(Constants.DatabasePath);

// Export / backup
await databaseService.CloseConnectionAsync();
File.Copy(Constants.DatabasePath,
    Path.Combine(FileSystem.CacheDirectory, "backup.db3"), overwrite: true);

Platform Paths for FileSystem.AppDataDirectory

Platform Location
Android /data/user/0/{package}/files
iOS App sandbox Library (iCloud-backed)
Mac Catalyst App sandbox Library/Application Support
Windows %LOCALAPPDATA%\Packages\{id}\LocalState

Common Patterns

// Raw SQL
var items = await db.QueryAsync<TodoItem>(
    "SELECT * FROM TodoItem WHERE Done = ?", 1);

// Multiple tables — add in GetDatabaseAsync()
await _database.CreateTableAsync<TodoItem>();
await _database.CreateTableAsync<Category>();

// Transactions
await db.RunInTransactionAsync(conn =>
{
    conn.Insert(item1);
    conn.Insert(item2);
});

// Drop and recreate
await db.DropTableAsync<TodoItem>();
await db.CreateTableAsync<TodoItem>();

Source: SKILL.md on GitHub

No alerts15d4 checks · Risk SAFE
  • Gen Agent Trust Hub15d

    The skill provides legitimate best practices and code templates for integrating SQLite databases into .NET MAUI applications. It correctly guides developers through package selection, thread-safe connection management, and platform-specific file handling without any malicious behavior.

  • Socket15d

    No alerts

  • Snyk15d

    Risk: LOW · No issues

  • Runlayer7mo

    1 file scanned · No issues

Signed by skilld at 74acbe3. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 6 months ago

README badge

README badge for davidortinau/maui-skills/maui-sqlite-database