SkillAgentSearch skills...

SoloDB

A document database built on top of SQLite with full LINQ/IQueryable support.

Install / Use

/learn @Unconcurrent/SoloDB
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

SoloDB - A Document Database With Full LINQ Support

Version 1.0 - Stable Release and Version 1.1 - Relational Support

SoloDB is a high-performance, lightweight, and robust embedded .NET database that elegantly combines the power of a NoSQL document store with the reliability of SQL. Built directly on top of SQLite and its native JSONB support, SoloDB offers a serverless, feature-rich experience, combining a simple MongoDB-like API with full LINQ support for expressive, strongly-typed queries.

SoloDB includes native relational-document support via DBRef<T>, DBRefMany<T>, and [SoloRef(...)], so you can model references and graph-like data while staying in a strongly-typed document API.

It is designed for developers who need a fast, reliable, and easy-to-use database solution without the overhead of a separate server. It's perfect for desktop applications, mobile apps (via .NET MAUI), and web applications.

I wrote a detailed comparison with a popular alternative, LiteDB — including benchmarks, API differences, and developer experience. Read the article here.

Table of Contents

Core Features

SoloDB is packed with features that provide a seamless and powerful developer experience.

  • SQLite Core: Leverages the world's most deployed database engine, ensuring rock-solid stability, performance, and reliability.
  • Serverless Architecture: As a .NET library, it runs in-process with your application. No separate server or configuration is required.
  • Hybrid NoSQL & SQL: Store and query schemaless JSON documents with a familiar object-oriented API, or drop down to raw SQL for complex queries.
  • Full LINQ Support: Use the full power of LINQ and IQueryable<T> to build expressive, strongly-typed queries against your data.
  • ACID Transactions: Guarantees atomicity, consistency, isolation, and durability for all operations, thanks to SQLite's transactional nature.
  • Expressive Indexing: Create unique or non-unique indexes on document properties for lightning-fast queries, using simple attributes.
  • Integrated File Storage: A robust, hierarchical file system API (similar to System.IO) for storing and managing large files and binary data directly within the database.
  • Polymorphic Collections: Store objects of different derived types within a single collection and query them by their base or concrete type.
  • Events API: Subscribe to collection lifecycle events (OnInserting, OnInserted, OnUpdating, OnUpdated, OnDeleting, OnDeleted) with full transactional guarantees via SQLite triggers.
  • Thread-Safe: A built-in connection pool ensures safe, concurrent access from multiple threads.
  • Customizable ID Generation: Use the default long primary key, or implement your own custom ID generation strategy (e.g., string, Guid).
  • .NET Standard 2.0 & 2.1: Broad compatibility with .NET Framework, .NET Core, and modern .NET runtimes.
  • Open Source: Licensed under the permissive LGPL-3.0.
  • Documentation: See the official documentation for detailed guides.

Why SoloDB?

In a world of countless database solutions, SoloDB was created to fill a specific niche: to provide a simple, modern, and powerful alternative to document databases like MongoDB, but with the unmatched reliability and zero-configuration nature of SQLite. It's for developers who love the flexibility of NoSQL but don't want to sacrifice the transactional integrity and robustness of a traditional SQL database.

Installation

Install SoloDB directly from the NuGet Package Manager.

dotnet add package SoloDB

Getting Started: A 60-Second Guide

Here is a complete example to get you up and running instantly.

using SoloDatabase;
using SoloDatabase.Attributes;

// 1. Initialize the database (on-disk or in-memory)
using var db = new SoloDB("my_app_data.db");

// 2. Get a strongly-typed collection
var users = db.GetCollection<User>();

// 3. Insert some data
var user = new User 
{ 
    Name = "John Doe", 
    Email = "john.doe@example.com", 
    CreatedAt = DateTime.UtcNow 
};
users.Insert(user);
Console.WriteLine($"Inserted user with auto-generated ID: {user.Id}");

// 4. Query your data with LINQ
var foundUser = users.FirstOrDefault(u => u.Email == "john.doe@example.com");
if (foundUser != null)
{
    Console.WriteLine($"Found user: {foundUser.Name}");

    // 5. Update a document
    foundUser.Name = "Johnathan Doe";
    users.Update(foundUser);
    Console.WriteLine("User has been updated.");
}

// 6. Delete a document
users.Delete(user.Id);
Console.WriteLine($"User deleted. Final count: {users.Count()}");

// Define your data model
public class User
{
    // A 'long Id' property is automatically used as the primary key.
    public long Id { get; set; }

    [Indexed] // Create an index on the 'Email' property for fast lookups.
    public string Email { get; set; }
    public string Name { get; set; }
    public DateTime CreatedAt { get; set; }
}

Usage and Examples

Initializing the Database

You can create a database on disk for persistence or in-memory for temporary data and testing.

using SoloDatabase;

// Create or open a database file on disk
using var onDiskDB = new SoloDB("path/to/database.db");

// Create a named, shareable in-memory database
using var sharedMemoryDB = new SoloDB("memory:my-shared-db");

Working with Collections

A collection is a container for your documents, analogous to a table in SQL.

// Get a strongly-typed collection. This is the recommended approach.
var products = db.GetCollection<Product>();

// Get an untyped collection for dynamic scenarios.
var untypedProducts = db.GetUntypedCollection("Product");

public class Product { /* ... */ }

Relations (DBRef, DBRefMany, SoloRef)

Overview

SoloDB relations are explicit, typed links between collections:

  • DBRef<TTarget>: single relation to one target row.
  • DBRefMany<TTarget>: many relation via link rows.
  • [SoloRef(...)]: relation policy annotation (OnDelete, OnOwnerDelete, Unique).

Relations are persisted through dedicated link tables (SoloDBRelLink_*) and relation metadata (SoloDBRelation), not embedded owner-document arrays of foreign keys.

DBRef and DBRefMany Basics

using SoloDatabase;
using SoloDatabase.Attributes;
using System.Collections.Generic;

public class Team
{
    public long Id { get; set; }
    public string Name { get; set; } = "";

    // Single relation
    public DBRef<Member> Lead { get; set; } = DBRef<Member>.None;

    // Many relation
    public DBRefMany<Member> Members { get; set; } = new();
}

public class Member
{
    public long Id { get; set; }
    public string Name { get; set; } = "";
}

using var db = new SoloDB("memory:relations-basics");
var teams = db.GetCollection<Team>();
var members = db.GetCollection<Member>();

// DBRef.To(existingId): link to an already persisted target.
var existingLeadId = members.Insert(new Member { Name = "Existing Alice" });
teams.Insert(new Team
{
    Name = "Ops",
    Lead = DBRef<Member>.To(existingLeadId)
});

// DBRef.From(entity): insert target first, then link owner to inserted target.
var team = new Team
{
    Name = "Core",
    Lead = DBRef<Member>.From(new Member { Name = "Alice" })
};

// DBRefMany supports Add/Clear/Remove mutations tracked on Update.
team.Members.Add(new Member { Name = "Bob" });
team.Members.Add(new Member { Name = "Carol" });

teams.Insert(team);

// Default policy behavior in this basics example:
// - No [SoloRef(...)] overrides are applied here.
// - One owner with one referenced Member: deleting the owner deletes that orphan Member (default OnOwnerDelete=Deletion).
// - Two owners sharing the same Member: deleting one owner keeps the shared Member; deleting the last owner deletes it.

SoloRef Policy Matrix

DeletePolicy values in SoloDB are: Restrict, Cascade, Unlink, Deletion.

| Policy Surface | Trigger Operation | Persistence Result | Reject Behavior | |---|---|---|---| | OnDelete = Restrict | Delete target while owners still reference it | Target delete blocked; links and owners unchanged | Typed reject (InvalidOperationException) | | OnDelete = Cascade | Delete target | Referencing owners are deleted (and their links removed) | N/A when valid | | OnDelete = Unlink | Delete target | Owner rows survive; relation links removed / refs become empty | N/A when valid | | OnOwnerDelete = Restrict | Delete owner that still has links | Owner delete blocked | Typed reject (InvalidOperationException) | | OnOwnerDelete = Unlink | Delete owner | Owner removed; links removed; targets survive | N/A when valid | | OnOwnerDelete = Deletion | Delete owne

View on GitHub
GitHub Stars51
CategoryData
Updated1d ago
Forks1

Languages

F#

Security Score

100/100

Audited on Mar 27, 2026

No findings