🚀 Getting Started with BLite
Get up and running with BLite in minutes. This guide will walk you through installation, basic setup, and your first CRUD operations.
Quick Install
Install BLite from NuGet:
dotnet add package BLiteThis single package includes:
- BLite.Core - The database engine
- BLite.Bson - Zero-allocation BSON serializer
- BLite.SourceGenerators - Compile-time mappers
Project Layout
Always define your DbContext and entity classes in their own .cs files with an explicit namespace. Placing them inside Program.cs using top-level statements (without a namespace declaration) causes the source generator to fail.
MyApp/
├── Program.cs // entry point — top-level statements are fine here
├── AppDbContext.cs // DbContext definition (must have a namespace)
└── Models/
└── User.cs // entity model (must have a namespace)The source generator derives the generated file namespace from your class's namespace. If your DbContext or entity types are declared in Program.cs inside a top-level program (i.e. without an explicit namespace block), the generator cannot build a valid file name and will emit a CS8785 error. Collections will not be initialised, and accessing them causes a NullReferenceException at runtime.
The fix is simple: move your DbContext and models to separate files with a namespace.
Create Your First Database
Define a model in its own file with a namespace:
// Models/User.cs
namespace MyApp.Models;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
[Table("users")]
public class User
{
[Key]
public ObjectId Id { get; set; }
[Required]
[StringLength(100)]
public string Name { get; set; } = "";
public int Age { get; set; }
public string Email { get; set; } = "";
}The [Key] property must be one of these types. Unsigned integers (uint, ushort, ulong) are not supported as primary key types and will cause source generation to fail.
| Type | Auto-generated on insert? | Notes |
|---|---|---|
ObjectId | ✅ Yes | Default recommendation |
string | ✅ Yes (CUID) | Since v3.4.0 |
Guid | ✅ Yes | Since v3.4.0 |
int | ❌ No — set manually | |
long | ❌ No — set manually |
Initialize the Database
Define the DbContext in its own file with a namespace. The class name must end in Context and be declared partial so the source generator can add the InitializeCollections() method.
// AppDbContext.cs
namespace MyApp;
using BLite.Core;
using MyApp.Models;
public sealed partial class AppDbContext : DocumentDbContext
{
public DocumentCollection<ObjectId, User> Users { get; set; } = null!;
public AppDbContext(string path) : base(path)
{
InitializeCollections();
}
}- Name must end in
Context— the generator scans for classes whose name ends inContext(e.g.AppDbContext,StoreContext). Names likeAppDatabaseorMyDbare not discovered. - Must be
partial— the generator adds theInitializeCollections()implementation as a partial class extension. - Must have a namespace — classes in the global namespace (top-level statements without an explicit
namespace) cause aCS8785build error. See the Project Layout section above. - Must inherit
DocumentDbContext— directly or through another context that also inherits it.
// Program.cs — consuming the context
using MyApp;
using var db = new AppDbContext("myapp.blite");
var users = db.Users;Basic CRUD
Insert
var newUser = new User
{
Name = "Alice",
Age = 30,
Email = "alice@example.com"
};
await users.InsertAsync(newUser);
Console.WriteLine($"Inserted with ID: {newUser.Id}");Query
// Find by ID
var user = await users.FindByIdAsync(newUser.Id, ct);
// Query with async LINQ
List<User> results = await users.AsQueryable()
.Where(u => u.Age > 25)
.OrderBy(u => u.Name)
.ToListAsync(ct);Update
user.Age = 31;
await users.UpdateAsync(user);Delete
await users.DeleteAsync(user.Id);BLite.Caching — IDistributedCache
Need a drop-in IDistributedCache for ASP.NET Core or any hosted .NET service? Install the companion package:
dotnet add package BLite.CachingRegister in ASP.NET Core
// Program.cs
builder.Services.AddBLiteDistributedCache("cache.db");
// With default TTL and auto-purge on open
builder.Services.AddBLiteDistributedCache("cache.db", new BLiteKvOptions
{
DefaultTtl = TimeSpan.FromMinutes(30),
PurgeExpiredOnOpen = true
});Typed helpers (IBLiteCache)
Inject IBLiteCache for typed get/set via System.Text.Json and a thundering-herd-safe GetOrSetAsync:
// Typed set
await cache.SetAsync("user:42", myUser,
new DistributedCacheEntryOptions { SlidingExpiration = TimeSpan.FromMinutes(20) });
// Typed get
User? user = await cache.GetAsync<User>("user:42");
// GetOrSet — one factory call even under concurrent load
User user = await cache.GetOrSetAsync<User>("user:42",
factory: async ct => await db.LoadUserAsync(42, ct),
options: new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
});IBLiteCache is a superset of IDistributedCache. The same AddBLiteDistributedCache() registration satisfies both interfaces — inject whichever fits your code. See Key-Value Store for the full API reference and raw KV usage.