redb.Export
1.2.14
Prefix Reserved
dotnet add package redb.Export --version 1.2.14
NuGet\Install-Package redb.Export -Version 1.2.14
<PackageReference Include="redb.Export" Version="1.2.14" />
<PackageVersion Include="redb.Export" Version="1.2.14" />
<PackageReference Include="redb.Export" />
paket add redb.Export --version 1.2.14
#r "nuget: redb.Export, 1.2.14"
#:package redb.Export@1.2.14
#addin nuget:?package=redb.Export&version=1.2.14
#tool nuget:?package=redb.Export&version=1.2.14
REDB — Entity Database for .NET
SQL speed. NoSQL flexibility. Pure C# schemas. Zero migrations.
REDB is an EAV-based database engine for .NET that stores typed objects as JSON properties in a relational backend (PostgreSQL, MSSQL). You define schemas as plain C# classes — REDB handles storage, indexing, querying, trees, lists, aggregation, and window functions through a single LINQ-style API.
Quick Start
// 1. Define a schema — that's your migration
[RedbScheme("Employee")]
public class EmployeeProps
{
public string FirstName { get; set; } = "";
public string LastName { get; set; } = "";
public int Age { get; set; }
public decimal Salary { get; set; }
public string Department { get; set; } = "";
public string[] Skills { get; set; } = [];
public Address? HomeAddress { get; set; }
public Dictionary<int, decimal>? BonusByYear { get; set; }
}
// 2. Sync scheme (creates storage automatically)
await redb.SyncSchemeAsync<EmployeeProps>();
// 3. Save
var emp = new RedbObject<EmployeeProps> {
name = "John Smith",
Props = new EmployeeProps { FirstName = "John", Salary = 95000, Skills = ["C#", "SQL"] }
};
await redb.SaveAsync(emp);
// 4. Query with full LINQ
var seniors = await redb.Query<EmployeeProps>()
.Where(e => e.Salary > 80000 && e.Skills.Contains("C#"))
.OrderByDescending(e => e.Salary)
.ToListAsync();
Packages
Installation
# PostgreSQL
dotnet add package redb.Core
dotnet add package redb.Postgres
# or MSSQL
dotnet add package redb.Core
dotnet add package redb.MSSql
# Pro (optional)
dotnet add package redb.Core.Pro
dotnet add package redb.Postgres.Pro # or redb.MSSql.Pro
Setup & InitializeAsync
using redb.Core;
using redb.Postgres; // or redb.MSSql
var builder = WebApplication.CreateBuilder(args);
// Register REDB
builder.Services.AddRedb(options =>
{
options.ConnectionString = "Host=localhost;Database=mydb;Username=postgres;Password=pass";
});
var app = builder.Build();
// Initialize with automatic schema creation
var redb = app.Services.GetRequiredService<IRedbService>();
await redb.InitializeAsync(ensureCreated: true);
Database Setup Options
REDB provides several ways to create the database schema:
Option A — Automatic on startup (recommended):
// Creates schema if missing, then initializes
await redb.InitializeAsync(ensureCreated: true);
Option B — Explicit call:
await redb.EnsureDatabaseAsync(); // idempotent — safe to call every time
await redb.InitializeAsync();
Option C — Export SQL script for DBA / CI:
var sql = redb.GetSchemaScript();
File.WriteAllText("redb_schema.sql", sql);
Option D — CLI tool:
dotnet tool install --global redb.CLI
# Create schema in an existing database
redb init --connection "Host=localhost;Database=mydb;..." --provider postgres
# Export SQL to file
redb schema --provider postgres --output redb_schema.sql
Capabilities
CRUD
| Feature | API | Notes |
|---|---|---|
| Save single object | SaveAsync(obj) |
Create or update |
| Load by ID | LoadAsync<T>(id) |
Returns RedbObject<T> with Props |
| Bulk insert | AddNewObjectsAsync(objects) |
Single round-trip via COPY protocol, replaces thousands of INSERTs |
| Batch save | SaveAsync(IEnumerable<IRedbObject>) |
Save multiple objects at once |
| Delete | DeleteAsync(id), DeleteWithPurgeAsync(ids) |
Single or batch delete with full purge |
| Load-modify-save | LoadAsync → modify → SaveAsync |
Standard update pattern |
Object Graph (RedbObject References in Props)
Props can contain RedbObject<T> properties — single, array, or dictionary. The entire graph is saved and loaded in one call. No JOINs, no Include chains, no manual assembly.
[RedbScheme]
public class OrderProps
{
public string Title { get; set; } = "";
// Single nested object with its own Props
public RedbObject<PaymentProps>? Payment { get; set; }
// Array of nested objects
public RedbObject<MetricsProps>[]? RelatedMetrics { get; set; }
// Dictionary of nested objects
public Dictionary<string, RedbObject<CouponProps>>? Coupons { get; set; }
}
// Save — entire graph persisted, ParentId set automatically
await redb.SaveAsync(order);
// Load — full graph reconstructed, all nested objects hydrated
var loaded = await redb.LoadAsync<OrderProps>(id);
// loaded.Props.Payment.Props — ready
// loaded.Props.RelatedMetrics[0].Props — ready
// loaded.Props.Coupons["SUMMER"].Props — ready
Nested objects are real RedbObject instances with their own id, name, DateCreate, DateModify, and Props. They can be queried independently, updated in place, and participate in tree structures.
Rich Props Structure
Props fields can be any combination of scalars, nested classes, collections, and dictionaries — arbitrarily deep. Everything is serialized, stored, and fully restored on load. No extra tables, no FKs, no mapping.
[RedbScheme("Analytics Record")]
public class AnalyticsRecordProps
{
// Scalars
public string Title { get; set; } = "";
public int Views { get; set; }
public decimal Revenue { get; set; }
// Primitive arrays
public string[]? Tags { get; set; }
public int[]? Scores { get; set; }
// Nested business class
public Address? HomeAddress { get; set; }
// Array of business classes
public Contact[]? Contacts { get; set; }
// Dictionary<string, primitive>
public Dictionary<string, string>? PhoneBook { get; set; }
// Dictionary<int, decimal>
public Dictionary<int, decimal>? PriceList { get; set; }
// Dictionary<string, nested class>
public Dictionary<string, Address>? AddressBook { get; set; }
// Dictionary<string, complex class with its own arrays and dicts>
public Dictionary<string, ProjectInfo>? ComplexBook { get; set; }
// Tuple key dictionary
public Dictionary<(int, string), string>? TupleKeyDict { get; set; }
}
public class Address
{
public string City { get; set; } = "";
public string Street { get; set; } = "";
public BuildingDetails? Details { get; set; } // nesting goes deeper
}
public class ProjectInfo
{
public string Title { get; set; } = "";
public int Priority { get; set; }
public string[]? Tags { get; set; } // arrays inside dict values
public MetricTag[]? MetricTags { get; set; } // class arrays inside dict values
public Dictionary<string, int>? Scores { get; set; } // dict inside dict value
}
All saved and loaded with a single SaveAsync / LoadAsync. Fields can be added or removed at any time — SyncSchemeAsync handles it.
Where Filters
| Feature | Example | Notes |
|---|---|---|
| Comparison | .Where(e => e.Salary > 75000) |
>, <, >=, <=, ==, != |
| AND / OR / NOT | .Where(e => e.Age >= 30 && e.Salary > 70000) |
Standard boolean logic |
| Chained Where | .Where(...).Where(...) |
Multiple calls = AND |
| WhereIn | .WhereIn(e => e.Department, values) |
SQL IN (...) clause |
| Nullable fields | .Where(e => e.Code == null) |
IS NULL / IS NOT NULL |
| Base field filters | .WhereRedb(o => o.DateCreate.Year == 2025) |
Filter on _objects table fields directly |
| WhereInRedb | .WhereInRedb(x => x.Id, ids) |
IN on base fields — no EAV join |
DateTime
| Feature | Example |
|---|---|
| Comparison | .Where(e => e.HireDate >= cutoffDate) |
| Range | .Where(e => e.HireDate >= start && e.HireDate < end) |
| Extract parts | .WhereRedb(o => o.DateCreate.Year == 2025) |
String Operations
| Feature | Example | SQL |
|---|---|---|
| Contains | .Where(e => e.Name.Contains("Smith")) |
LIKE '%Smith%' |
| StartsWith | .Where(e => e.Name.StartsWith("John")) |
LIKE 'John%' |
| Case-insensitive | .Contains("smith", StringComparison.OrdinalIgnoreCase) |
ILIKE |
| ToLower / ToUpper | .Where(e => e.Name.ToLower().Contains("s")) |
LOWER() |
| Trim + Length | .Where(e => e.Name.Trim().Length > 3) |
TRIM(), LENGTH() |
Nested Properties
| Feature | Example |
|---|---|
| Nested class field | .Where(e => e.HomeAddress!.City == "London") |
| Deep nesting (3+ levels) | .Where(e => e.HomeAddress!.Building!.Floor > 10) |
Array Operations
| Feature | Example |
|---|---|
| Contains element | .Where(e => e.Skills.Contains("C#")) |
| Contains any (OR) | .Where(e => e.Skills.Contains("C#") \|\| e.Skills.Contains("Python")) |
| Contains all (AND) | .Where(e => e.Skills.Contains("C#") && e.Skills.Contains("SQL")) |
| Exclude element | .Where(e => e.Skills.Contains("C#") && !e.Skills.Contains("intern")) |
| Mixed with scalars | .Where(e => e.Age > 30 && e.Skills.Contains("C#")) |
Dictionary Operations
| Feature | Example |
|---|---|
| ContainsKey | .Where(e => e.PhoneDirectory!.ContainsKey("desk")) |
| Indexer filter | .Where(e => e.BonusByYear![2023] > 6000) |
| Nested class in value | .Where(e => e.Locations!["HQ"].City == "NY") |
| Tuple key | .Where(e => e.Reviews![reviewKey] == "Excellent") |
Projection & Pagination
| Feature | API | Notes |
|---|---|---|
| Select fields | .Select(x => new { x.Props.FirstName, x.Props.Salary }) |
Server-side projection, fetches only selected columns |
| Distinct | .Distinct() |
Dedup by Props hash |
| DistinctBy | .DistinctBy(x => x.Field), .DistinctByRedb(x => x.Name) |
Distinct on specific field |
| OrderBy | .OrderBy(e => e.Salary), .OrderByDescending(...) |
Ascending / descending |
| ThenBy | .ThenBy(...), .ThenByDescending(...) |
Multi-field sorting |
| Skip / Take | .Skip(10).Take(10) |
Pagination |
| FirstOrDefault | .FirstOrDefaultAsync() |
Single result or null |
Existence & Count
| Feature | API |
|---|---|
| Count | .CountAsync() |
| Any | .AnyAsync(), .AnyAsync(predicate) |
| All | .AllAsync(predicate) |
Arithmetic & Math
| Feature | Example | SQL |
|---|---|---|
| Arithmetic in Where | .Where(e => e.Salary * 12 > 1_000_000) |
Inline *, /, +, - |
| Multi-field formulas | .Where(e => e.Age * 1000 + e.Salary > 120_000) |
Combined expressions |
| Math.Abs | .Where(e => Math.Abs(e.Age - 35) <= 5) |
ABS() |
| Arbitrary SQL function | Sql.Function<T>("COALESCE", e.Age, 0) |
Any SQL function by name |
Aggregation
| Feature | API | Notes |
|---|---|---|
| Sum | .SumAsync(e => e.Salary) |
Server-side SUM |
| Average | .AverageAsync(e => e.Age) |
Server-side AVG |
| Min / Max | .MinAsync(e => e.Salary), .MaxAsync(...) |
Server-side MIN / MAX |
| Batch aggregation | .AggregateAsync(x => new { Agg.Sum(...), Agg.Average(...), Agg.Count() }) |
Multiple aggregations in one query |
| Filtered aggregation | .Where(...).SumAsync(...) |
Filter before aggregating |
| Base-field aggregation | .SumRedbAsync(x => x.Id), .MinRedbAsync(x => x.DateCreate) |
Aggregate on _objects fields — no EAV join |
| Array element aggregation | Agg.Sum(x.Props.SkillLevels.Select(s => s)) |
Sum all array elements |
GroupBy
| Feature | API | Notes |
|---|---|---|
| Group by field | .GroupBy(x => x.Department).SelectAsync(g => new { g.Key, Agg.Sum(g, x => x.Salary) }) |
Server-side GROUP BY |
| Filter + group | .Where(...).GroupBy(...) |
WHERE before GROUP BY |
| Composite key | .GroupBy(x => new { x.Department, x.Position }) |
Multi-field grouping |
| Group by base field | .GroupByRedb(x => x.OwnerId) |
GROUP BY on _objects — no EAV join |
| Group by array element | .GroupByArray(e => e.Contacts!, c => c.Type) |
Expands arrays into groups |
Window Functions
| Feature | API | Notes |
|---|---|---|
| ROW_NUMBER | Win.RowNumber() |
Rank within partition |
| RANK / DENSE_RANK | Win.Rank(), Win.DenseRank() |
Ranking with/without gaps |
| Running sum | Win.Sum(x.Props.Salary) |
Cumulative aggregation |
| LAG / LEAD | Win.Lag(x.Props.Salary), Win.Lead(...) |
Previous / next row values |
| FIRST_VALUE / LAST_VALUE | Win.FirstValue(...), Win.LastValue(...) |
Boundary values in partition |
| NTILE | Win.Ntile(4) |
Divide into equal buckets |
| Custom frame | .Frame(Frame.Rows(3)) |
Sliding window: ROWS BETWEEN N PRECEDING AND CURRENT ROW |
| Partition by base field | .PartitionByRedb(x => x.SchemeId) |
No EAV join |
| Filter + window | .Where(...).WithWindow(...) |
Pre-filter before windowing |
| GroupBy + window | .GroupBy(...).WithWindow(...).SelectAsync(...) |
Rank aggregated groups |
Tree Structures
Built-in hierarchical data with closure-table storage and recursive CTEs.
| Feature | API | Notes |
|---|---|---|
| Create child | CreateChildAsync(child, parent) |
Single node creation |
| Bulk create | AddNewObjectsAsync(treeObjects) |
Batch insert with pre-assigned IDs |
| Load tree | LoadTreeAsync<T>(root, maxDepth) |
Full hierarchy with depth limit |
| Get children | GetChildrenAsync<T>(parent) |
Direct children only |
| Get descendants | GetDescendantsAsync<T>(node) |
All descendants recursively |
| Path to root | GetPathToRootAsync<T>(node) |
Breadcrumb trail |
| Move subtree | MoveObjectAsync(node, newParent) |
Reparent node and its subtree |
| Tree LINQ queries | TreeQuery<T>().Where(...).OrderBy(...) |
Full LINQ on tree |
| Filter roots | .WhereRoots() |
Root nodes only |
| Filter leaves | .WhereLeaves() |
Leaf nodes only |
| Filter by level | .WhereLevel(2) |
Nodes at specific depth |
| Scoped subtree query | TreeQuery<T>(rootId, maxDepth) |
Query within a subtree |
| Multiple roots | TreeQuery<T>(parents[], maxDepth) |
Query across subtrees |
| Ancestor filter | .WhereHasAncestor<T>(a => a.Budget > 500000) |
Filter by ancestor properties |
| Descendant filter | .WhereHasDescendant<T>(d => d.Budget > 100000) |
Filter by descendant properties |
| Relationship check | node.IsDescendantOfAsync(ancestor) |
Without loading tree |
| DFS / BFS traversal | .DepthFirstTraversal(), .BreadthFirstTraversal() |
In-memory traversal |
| Tree materialization | .ToTreeListAsync(), .ToRootListAsync(), .ToFlatListAsync() |
Parent chains, recursive children, or flat |
| Tree stats | TreeCollection<T>.GetStats() |
Depth, leaf count, max width |
| Aggregation on trees | TreeQuery<T>().GroupBy(...), .WithWindow(...) |
GroupBy and window functions in tree context |
Lists (Reference Dictionaries)
Named lookup lists with items, useful for statuses, categories, roles.
| Feature | API |
|---|---|
| Create list | RedbList.Create(name, alias) |
| Add items | ListProvider.AddItemsAsync(list, values, aliases) |
| Get by name | ListProvider.GetListByNameAsync(name) |
| Item with linked object | RedbListItem(list, value, alias, linkedObject) |
| Store in Props | Props.Status = listItem (single), Props.Roles = listItems (array) |
| Filter by item value | .Where(p => p.Status!.Value == "Active") |
| Filter by item identity | .Where(p => p.Status == activeItem) |
| WhereIn on item values | .WhereIn(p => p.Status!.Value, values) |
| Any in item array | .Where(p => p.Roles!.Any(r => r.Value == "Admin")) |
Export
| Format | Notes |
|---|---|
| CSV | Flat or nested, configurable delimiters |
| JSON | Structured export with metadata |
| XML | Full object graph |
| YAML | Human-readable |
| Markdown | Table or document format |
Users, Roles & Permissions
Built-in user management with password hashing, roles, and object-level permissions. No external identity provider required.
| Feature | API | Notes |
|---|---|---|
| Create user | UserProvider.CreateUserAsync(request) |
Login, password, name, email, phone |
| Authenticate | UserProvider.ValidateUserAsync(login, password) |
Returns IRedbUser?, SHA256 + salt |
| Change password | UserProvider.ChangePasswordAsync(userId, old, new) |
Verifies old password first |
| Enable / disable | UserProvider.EnableUserAsync(id), DisableUserAsync(id) |
Soft disable |
| Search users | UserProvider.GetUsersAsync(criteria) |
Filter by login, email, role, date range |
| Create role | RoleProvider.CreateRoleAsync(request) |
Named role with optional description |
| Assign role | RoleProvider.AssignUserToRoleAsync(userId, roleId) |
Many-to-many |
| Grant permission | GrantPermissionAsync(request) |
Per-object or per-scheme, CRUD flags |
| Check permission | CanUserSelectObject(objectId) |
Select / Insert / Update / Delete |
| Effective permissions | GetEffectivePermissionsAsync(userId, objectId) |
Resolved from user + role inheritance |
| Security context | SetCurrentUser(user), CreateSystemContext() |
Ambient via AsyncLocal, disposable elevation |
// Authenticate
var user = await redb.UserProvider.ValidateUserAsync("admin", "password123");
if (user != null)
{
redb.SetCurrentUser(user);
// All subsequent operations run as this user
}
// Temporary system elevation (skip permissions)
using (redb.CreateSystemContext())
{
await redb.SaveAsync(sensitiveObject);
}
Architecture
IRedbService ← single entry point
├── Query<T>() ← flat LINQ queries
├── TreeQuery<T>() ← hierarchical queries
├── SaveAsync() ← create / update
├── LoadAsync<T>() ← load by ID
├── ListProvider ← reference dictionaries
├── UserProvider ← users, authentication, passwords
├── RoleProvider ← roles and user-role assignments
├── SecurityContext ← current user, permission checks
└── SyncSchemeAsync() ← auto-migration from C# class
Storage is provider-based. Each [RedbScheme] class maps to an EAV structure in the target database. Schema changes (new fields, removed fields, type changes) are handled automatically by SyncSchemeAsync — no migration files needed.
Supported backends: PostgreSQL, Microsoft SQL Server.
Pro
REDB Pro unlocks faster query execution, parallel materialization, deep nested property queries, arithmetic and math expressions in WHERE, Sql.Function<T>() for calling arbitrary SQL functions, change tracking, schema migrations, and advanced analytics (window functions over grouped data). If performance matters — use Pro.
License
Core packages (redb.Core, redb.Postgres, redb.MSSql) are MIT-licensed.
Pro packages require a commercial license — see LICENSE-PRO.txt.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. 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. |
-
net10.0
- Microsoft.Data.SqlClient (>= 5.2.2)
- Npgsql (>= 9.0.3)
-
net8.0
- Microsoft.Data.SqlClient (>= 5.2.2)
- Npgsql (>= 9.0.3)
-
net9.0
- Microsoft.Data.SqlClient (>= 5.2.2)
- Npgsql (>= 9.0.3)
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 |
|---|---|---|
| 1.2.14 | 79 | 2/13/2026 |