LumDbEngine 2.2.3

dotnet add package LumDbEngine --version 2.2.3
                    
NuGet\Install-Package LumDbEngine -Version 2.2.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="LumDbEngine" Version="2.2.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="LumDbEngine" Version="2.2.3" />
                    
Directory.Packages.props
<PackageReference Include="LumDbEngine" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add LumDbEngine --version 2.2.3
                    
#r "nuget: LumDbEngine, 2.2.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package LumDbEngine@2.2.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=LumDbEngine&version=2.2.3
                    
Install as a Cake Addin
#tool nuget:?package=LumDbEngine&version=2.2.3
                    
Install as a Cake Tool

LumDb 2.2.3

A single-file, thread-safe embedded database for .NET 10. 100% C#, AOT-friendly, no native dependencies.

On-disk format 1.3.9 (DbHeader.VERSION = 1_003_009). Packed as major * 1_000_000 + minor * 1_000 + patch. Bump that constant only when the layout or engine contract changes — there is no runtime “append version” API. DbEngine.Version / VersionString expose the file format ("1.3.9"). The NuGet package version (2.2.0) is independent.

Engines

using var mem = new DbEngine();              // in-memory; same instance shares one committed image
using var disk = new DbEngine(@"d:\app.db"); // file + WAL

using (var ts = mem.StartTransaction())
{
    ts.Create<Student>("students");
    ts.Insert("students", new Student { Name = "lj", Age = 20 });
} // Dispose commits. The next StartTransaction on this engine sees the data.

mem.SaveTo(@"d:\app.db");                    // dump committed image (not uncommitted dirty pages)
Memory new DbEngine() File new DbEngine(path)
Persistence Process lifetime Disk + .log WAL
Cross-transaction Same instance shares the committed image Same, via the file
Discard Drops the current tx only Same
Crash recovery N/A Replay .log
SaveTo(path) Full committed dump File copy of committed image

SaveChanges / Dispose commit. Discard rolls back the current transaction and reloads from the committed image. A following Dispose does not overwrite the image with an empty cache.

LumEntity (source generator)

Mark a partial class. Build generates ILumEntity<T> (works without PublishAOT — generation is compile-time).

[LumEntity]
public partial class Student
{
    [Id] public uint Id { get; set; }          // engine auto row id, not a column
    [Key] [Str32B] public string Name { get; set; } = "";
    public int Age { get; set; }
    public bool Active { get; set; }
}

Unsupported nested members on [LumEntity] are skipped with warning LUMDB002. [Ignore] is silent. DateTime columns are UTC (DateTimeKind.Utc).

Tuple / DbCell API (no entity type):

ts.Create("kv", [("k", DbValueType.Int, true), ("v", DbValueType.StrVar, false)]);
ts.Insert("kv", [("k", 1), ("v", "hello")]);
var row = ts.Find("kv", "k", 1);
Console.WriteLine(row.Row.GetString(1));

Query (LINQ)

Where / Join / Skip / Take only build a plan (no I/O). ToList / Count / Delete / Exists run the whole plan under one transaction lock. The thread that called Query() must consume that instance; other threads call Query() themselves.

Scan uses RowView (no entity new until the result window). Count and WhereExists do not materialize inner rows.

using (var ts = eng.StartTransaction())
{
    var page = ts.Query<Student>("students")
        .Where(s => s.Active && s.Name.Trim().ToUpper().StartsWith("LJ"))
        .OrderByDescending(s => s.Age)
        .Skip(0)
        .Take(20)
        .ToList();

    var n = ts.Query<Student>("students").Where(s => s.Age >= 18).Count();

    var pairs = ts.Query<Student>("students")
        .Join<Order>("orders", (s, o) => s.Id == o.StudentId && o.Status == 1)
        .Where((s, o) => o.Amount >= 10)
        .ToList(); // List<(Student Outer, Order Inner)>

    var withOrders = ts.Query<Student>("students")
        .WhereExists<Order>("orders", (s, o) => s.Id == o.StudentId)
        .ToList();
}

Hand-written IDbEntity: Query_Entity<T> / JoinEntity. Three-table: .Join<A>(...).Join<B>(...) → List<(T1 A, T2 B, T3 C)>.

Expressions

Translated to a RowView tree (AOT: no Expression.Compile of the whole lambda):

  • Comparisons == != < <= > >=, logic && || !, arithmetic + - * / %
  • String (Ordinal / Invariant, one-argument overloads): StartsWith / EndsWith / Contains / Equals, ToUpper / ToLower (and *Invariant), Trim / TrimStart / TrimEnd, Substring, Replace, IndexOf / LastIndexOf, Length, IsNullOrEmpty / IsNullOrWhiteSpace, ToString()
  • Math: Abs Sign Min Max Clamp Floor Ceiling Truncate Round Sqrt Pow Sin Cos Tan Log Log10 Exp
  • Nesting is allowed: s.Name.Trim().ToUpper().Contains("LJ"), Math.Abs(Add(s.Age, 0))

Your own methods and captured Func (any TResult, not void / Action) are invoked per matching row:

static int Add(int a, int b) => a + b;
static string Fold(string s) => s.Trim().ToUpperInvariant();

ts.Query<Student>("students").Where(s => Add(s.Age, 1) > 18);
ts.Query<Student>("students").Where(s => Fold(s.Name).Contains("LJ"));

Func<string, bool> rx = n => System.Text.RegularExpressions.Regex.IsMatch(n, "^lj");
ts.Query<Student>("students").Where(s => rx(s.Name));

C# rejects Action in Where (predicate must be bool). Local functions inside the method cannot appear in expression trees (CS8110). System.* instance APIs that are not in the list (Split, Contains(..., StringComparison), ToUpper(culture), ternary ?:) compile, then throw LumException at ToList / Count.

Zero-alloc predicate: Where((ref RowView row) => row.GetInt(1) > 90). Entity callback (allocates every scanned row): WhereCallback(s => ...).

Performance notes

  • Count / Take / Join / WhereExists vs loading every entity (Find all, or skipping by new T()): scan stays on RowView; only the result window is boxed. That is the large win (see BenchLumDb GoThrough vs object scan, entity page vs Find all).
  • Whitelist string/Math nesting is the same RowOp path as a simple comparison.
  • Captured Func and user MethodInfo.Invoke run managed IL per row — correct, not faster than RowOp.
  • Equi-join is hash; inequality join is nested-loop over inner ids (O(N×M) CPU, still no full-table entity alloc). OrderBy on a join materializes all matching ids before Skip/Take.

Features

  • Relational tables with optional multi-key secondary indexes
  • Types: bool, byte, int/uint, long/ulong, float/double, decimal, DateTime UTC, fixed/var string, fixed/var bytes
  • Fluent Query / Join / WhereExists (one lock per terminal)
  • Read-committed: a readonly transaction sees the last commit, not another writer’s dirty pages
  • Thread-safe: one writer (upgradeable) + concurrent readers
  • Source-generated entities; GoThrough / RowView scan without allocating entities
  • AOT publish supported (PublishAot); daily dotnet build still runs the generator
  • Tools: LumDbExplorer (WinForms) to create/copy databases, create tables, CRUD rows, inspect schema and stats

Getting started

  1. Reference LumDbEngine (net10). For [LumEntity], the analyzer is packed with the NuGet.
  2. new DbEngine() or new DbEngine(path).
  3. using var ts = engine.StartTransaction(); — dispose to commit, or Discard().

License

MIT. See LICENSE.txt.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.2.3 96 9/12/2026
2.2.2 109 9/3/2026
2.2.1 93 9/3/2026
2.2.0 93 8/27/2026
2.1.0 111 8/26/2026
1.3.8 143 7/1/2026
1.3.6 252 11/6/2025
1.3.5 222 10/30/2025
1.3.4 200 9/28/2025
1.3.1.1 217 7/17/2025
1.3.1 210 7/17/2025
1.2.1 211 7/8/2025
1.1.4 279 3/7/2025
1.1.2 200 1/26/2025
1.1.1 170 1/22/2025
1.0.6 159 1/14/2025
1.0.5 167 1/13/2025
1.0.1 183 11/21/2024
1.0.0 168 11/16/2024

2.2.0: fluent Query/Join/WhereExists, expression Where (string/Math/user methods), window materialization on RowView.