SQLite Advanced Patterns
Leverage SQLite for embedded databases and edge computing.
By EMEPublished: February 20, 2025
sqliteembedded databaseedge computingpatterns
A Simple Analogy
SQLite is like a personal database librarian. Instead of going to a central library (server), you keep your database with you wherever you go.
Why SQLite?
- Serverless: No separate server needed
- Lightweight: Single file
- Portable: Works on any device
- ACID compliant: Data integrity
- Edge computing: Perfect for IoT
Setup and Connections
using System.Data.SQLite;
// Connection string
const string connectionString = "Data Source=mydb.sqlite;Version=3;";
// Using Entity Framework
builder.Services.AddDbContext<AppContext>(options =>
options.UseSqlite("Data Source=app.db")
);
// Direct connection
using (var connection = new SQLiteConnection(connectionString))
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = "SELECT * FROM Users WHERE Id = @id";
command.Parameters.AddWithValue("@id", 1);
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(reader["Name"]);
}
}
}
}
Full-Text Search
-- Create FTS table
CREATE VIRTUAL TABLE articles_fts USING fts5(
id,
title,
content,
category
);
-- Insert data
INSERT INTO articles_fts SELECT id, title, content, category FROM articles;
-- Search
SELECT * FROM articles_fts WHERE articles_fts MATCH 'database AND optimization' LIMIT 10;
// In C#
var results = await context.Articles
.FromSqlRaw("SELECT * FROM articles_fts WHERE articles_fts MATCH @query",
new SqliteParameter("@query", searchTerm))
.ToListAsync();
JSON Support
-- Store JSON data
CREATE TABLE config (
id INTEGER PRIMARY KEY,
name TEXT,
settings JSON
);
INSERT INTO config VALUES (1, 'app', '{"theme": "dark", "language": "en"}');
-- Query JSON
SELECT name, json_extract(settings, '$.theme') as theme FROM config;
-- Update JSON
UPDATE config SET settings = json_set(settings, '$.theme', 'light') WHERE id = 1;
Transactions
using (var transaction = connection.BeginTransaction())
{
try
{
var cmd1 = connection.CreateCommand();
cmd1.CommandText = "UPDATE accounts SET balance = balance - 100 WHERE id = 1";
cmd1.ExecuteNonQuery();
var cmd2 = connection.CreateCommand();
cmd2.CommandText = "UPDATE accounts SET balance = balance + 100 WHERE id = 2";
cmd2.ExecuteNonQuery();
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
throw;
}
}
Indexing
-- Create index on frequently searched columns
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_orders_customer ON orders(customer_id, status);
-- Analyze for optimization
ANALYZE;
-- Get query plan
EXPLAIN QUERY PLAN SELECT * FROM orders WHERE customer_id = 1 AND status = 'pending';
Offline-First Sync
public class SyncService
{
private readonly SqliteConnection _localDb;
private readonly HttpClient _api;
public async Task SyncAsync()
{
try
{
// Get changes from server
var remoteChanges = await _api.GetAsync("/api/sync/changes");
// Merge into local database
using (var transaction = _localDb.BeginTransaction())
{
foreach (var change in remoteChanges)
{
await ApplyChangeAsync(_localDb, change);
}
transaction.Commit();
}
// Push local changes to server
var localChanges = GetLocalChanges();
await _api.PostAsync("/api/sync/push", localChanges);
}
catch (HttpRequestException)
{
// No connection, work offline
Console.WriteLine("Working offline");
}
}
}
Best Practices
- WAL mode: Enable Write-Ahead Logging for concurrency
- Pragma settings: Optimize for your use case
- Regular backups: Automatic snapshots
- Connection pooling: Reuse connections
- Index wisely: Test before creating
Related Concepts
- Database replication
- Conflict resolution
- Edge computing
- Offline-first architecture
Summary
SQLite provides a lightweight, serverless database perfect for embedded applications and offline-first systems. Use full-text search, JSON, and transactions for powerful local data management.