Getting Started

Get CSharpDB up and running in your .NET project in minutes. Choose the API that fits your needs.

Installation

dotnet add package CSharpDB

This meta-package includes the storage engine, SQL engine, Collection API, ADO.NET provider, and diagnostics. For finer control, install individual packages like CSharpDB.Storage, CSharpDB.Engine, or CSharpDB.Data.

Option 1: SQL via ADO.NET

The most familiar approach for .NET developers. Use standard DbConnection, DbCommand, and DbDataReader APIs.

using CSharpDB.Data;

await using var conn = new CSharpDbConnection("Data Source=myapp.db");
await conn.OpenAsync();

// Create a table
await using var cmd = conn.CreateCommand();
cmd.CommandText = @"
    CREATE TABLE IF NOT EXISTS Products (
        Id    INTEGER PRIMARY KEY,
        Name  TEXT NOT NULL,
        Price REAL
    )";
await cmd.ExecuteNonQueryAsync();

// Insert rows with parameters
cmd.CommandText = "INSERT INTO Products VALUES (@id, @name, @price)";
cmd.Parameters.Clear();
cmd.Parameters.Add(new CSharpDbParameter("@id", 1));
cmd.Parameters.Add(new CSharpDbParameter("@name", "Widget"));
cmd.Parameters.Add(new CSharpDbParameter("@price", 9.99));
await cmd.ExecuteNonQueryAsync();

// Query
cmd.CommandText = "SELECT Id, Name, Price FROM Products WHERE Price > @minPrice";
cmd.Parameters.Clear();
cmd.Parameters.Add(new CSharpDbParameter("@minPrice", 5.0));
await using var reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
    Console.WriteLine($"{reader.GetString(1)}: ${reader.GetDouble(2):F2}");
}

Option 2: Engine API with SQL

Use the Database class directly for a lightweight, high-performance approach.

using CSharpDB.Engine;

await using var db = await Database.OpenAsync("myapp.db");

// Execute SQL directly
await db.ExecuteAsync(@"
    CREATE TABLE Users (
        Id    INTEGER PRIMARY KEY,
        Name  TEXT NOT NULL,
        Email TEXT
    )");

await db.ExecuteAsync("INSERT INTO Users VALUES (1, 'Alice', 'alice@example.com')");
await db.ExecuteAsync("INSERT INTO Users VALUES (2, 'Bob', 'bob@example.com')");

await using var results = await db.ExecuteAsync("SELECT Name, Email FROM Users ORDER BY Name");
while (await results.MoveNextAsync())
{
    Console.WriteLine($"{results.Current[0].AsText}: {results.Current[1].AsText}");
}

Option 3: Collection API (NoSQL)

Work with typed C# objects — no SQL needed. Built-in JSON serialization and indexing.

using CSharpDB.Engine;

public record Product(string Name, double Price, string[] Tags);

await using var db = await Database.OpenAsync("myapp.db");
var products = await db.GetCollectionAsync<Product>("products");

// Store objects
await products.PutAsync("widget", new("Widget", 9.99, ["tools", "hardware"]));
await products.PutAsync("gadget", new("Gadget", 24.99, ["electronics"]));

// Retrieve
var widget = await products.GetAsync("widget");

// Index a property and query
await products.EnsureIndexAsync(p => p.Name);
await foreach (var match in products.FindByIndexAsync(p => p.Name, "Gadget"))
    Console.WriteLine(match.Key);

// Scan all
await foreach (var entry in products.ScanAsync())
    Console.WriteLine($"{entry.Key}: {entry.Value.Name}: ${entry.Value.Price:F2}");

Option 4: Low-Level Storage API

For maximum control, use the storage engine directly with B+trees, pages, and the WAL.

using CSharpDB.Storage.BTrees;
using CSharpDB.Storage.Paging;
using CSharpDB.Storage.StorageEngine;

var storageOptions = new StorageEngineOptionsBuilder()
    .UsePagerOptions(new PagerOptions { MaxCachedPages = 1024 })
    .UseBTreeIndexes()
    .Build();

var factory = new DefaultStorageEngineFactory();
await using var ctx = await factory.OpenAsync("myapp.db", storageOptions);

await ctx.Pager.BeginTransactionAsync();
try
{
    uint rootPageId = await BTree.CreateNewAsync(ctx.Pager);
    var tree = new BTree(ctx.Pager, rootPageId);

    await tree.InsertAsync(1, new byte[] { 1, 2, 3, 4 });
    byte[]? payload = await tree.FindAsync(1);

    await ctx.Pager.CommitAsync();
}
catch
{
    await ctx.Pager.RollbackAsync();
    throw;
}

Custom Configuration

Fine-tune the storage engine for your workload.

using CSharpDB.Engine;

var options = new DatabaseOptions()
    .ConfigureStorageEngine(builder =>
    {
        builder.UseDirectLookupOptimizedPreset();
    });

await using var db = await Database.OpenAsync("myapp.db", options);

// Also available: in-memory and hybrid modes
await using var mem = await Database.OpenInMemoryAsync();
await using var hybrid = await Database.OpenHybridAsync(
    "myapp.db",
    new DatabaseOptions(),
    new HybridDatabaseOptions
    {
        PersistenceMode = HybridPersistenceMode.IncrementalDurable,
        HotTableNames = ["Products"]
    });