Code Examples

Learn RedBase by example. Browse working code samples for LINQ queries, bulk operations, tree structures, and more.

Data Model - EmployeeProps Click to view data model used in all examples
Tag with priority for categorization.
/// <summary>
/// Tag with priority for categorization.
/// </summary>
public class Tag
{
    public string Name { get; set; } = string.Empty;
    public int Priority { get; set; }
    public string? Description { get; set; }
}

/// <summary>
/// Project metrics for analytics.
/// </summary>
[RedbScheme("ProjectMetrics")]
public class ProjectMetricsProps
{
    public long ProjectId { get; set; }
    public long? TasksCompleted { get; set; }
    public long? TasksTotal { get; set; }
    public long? BugsFixed { get; set; }
    public double? Budget { get; set; }
    public long? TeamSize { get; set; }
    public Tag[]? Tags { get; set; }
    public string[]? Technologies { get; set; }
}

/// <summary>
/// Address with city, street and building details.
/// </summary>
public class Address
{
    public string City { get; set; } = string.Empty;
    public string Street { get; set; } = string.Empty;
    public BuildingInfo? Building { get; set; }
}

/// <summary>
/// Building information with floor and amenities.
/// </summary>
public class BuildingInfo
{
    public int Floor { get; set; }
    public string Name { get; set; } = string.Empty;
    public string[]? Amenities { get; set; }
    public int[]? AccessCodes { get; set; }
    public string[]? ParkingSpots { get; set; }
    public int[]? ElevatorFloors { get; set; }
}

/// <summary>
/// Contact detail key-value pair.
/// </summary>
public class ContactDetail
{
    public string Label { get; set; } = string.Empty;
    public string Value { get; set; } = string.Empty;
}

/// <summary>
/// Contact information (email, phone, etc).
/// </summary>
public class Contact
{
    public string Type { get; set; } = string.Empty;
    public string Value { get; set; } = string.Empty;
    public bool IsVerified { get; set; }
    public int[]? NotificationHours { get; set; }
    public ContactDetail[]? Metadata { get; set; }
}

/// <summary>
/// Department info with tags, metrics and nested budget data.
/// </summary>
public class Department
{
    public string Name { get; set; } = string.Empty;
    public int HeadCount { get; set; }
    public string[] Projects { get; set; } = [];
    public Tag[] Leaders { get; set; } = [];
    public Dictionary<string, int>? BudgetByYear { get; set; }
}

/// <summary>
/// Employee props - main model for examples.
/// Demonstrates all supported types:
/// - Simple types (int, string, DateTime, long, decimal)
/// - Arrays (string[], int[])
/// - Business classes (Address with nested BuildingInfo)
/// - Array of business classes (Contact[])
/// - RedbObject references (CurrentProject, PastProjects[])
/// - Dictionary types (various key and value types)
/// </summary>
[RedbScheme("Employee")]
public class EmployeeProps
{
    // Basic info
    public string FirstName { get; set; } = string.Empty;
    public string LastName { get; set; } = string.Empty;
    public int Age { get; set; }
    public DateTime HireDate { get; set; }
    public string Position { get; set; } = string.Empty;
    public decimal Salary { get; set; }
    public string Department { get; set; } = string.Empty;
    public string? EmployeeCode { get; set; }

    // Skills and certifications (arrays)
    public string[]? Skills { get; set; }
    public int[]? SkillLevels { get; set; }
    public string[]? Certifications { get; set; }
    public int[]? CertificationYears { get; set; }

    // Addresses (business classes)
    public Address? HomeAddress { get; set; }
    public Address? WorkAddress { get; set; }
    public Address? EmergencyAddress { get; set; }

    // Contacts (array of business classes)
    public Contact[]? Contacts { get; set; }

    // Project references (RedbObject)
    public RedbObject<ProjectMetricsProps>? CurrentProject { get; set; }
    public RedbObject<ProjectMetricsProps>[]? PastProjects { get; set; }

    // Phone directory: extension -> phone number
    public Dictionary<string, string>? PhoneDirectory { get; set; }

    // Office locations by city
    public Dictionary<string, Address>? OfficeLocations { get; set; }

    // Bonus history by year
    public Dictionary<int, decimal>? BonusByYear { get; set; }

    // Department details with complex nested data (Pro)
    public Dictionary<string, Department>? DepartmentHistory { get; set; }

    // Composite key: (year, quarter) -> performance score (Pro)
    public Dictionary<(int Year, string Quarter), string>? PerformanceReviews { get; set; }

    // Project metrics by code (Pro)
    public Dictionary<string, RedbObject<ProjectMetricsProps>>? ProjectMetrics { get; set; }
}

/// <summary>
/// Department props for tree examples (corporate hierarchy).
/// Used with TreeRedbObject for organizational structure.
/// Similar to CategoryTestProps in ConsoleTest.
/// </summary>
[RedbScheme("Department")]
public class DepartmentProps
{
    /// <summary>Department name (e.g. "IT Department Moscow").</summary>
    public string Name { get; set; } = string.Empty;

    /// <summary>Description (e.g. "Software development team").</summary>
    public string Description { get; set; } = string.Empty;

    /// <summary>Is department active?</summary>
    public bool IsActive { get; set; } = true;

    /// <summary>Budget in USD.</summary>
    public decimal Budget { get; set; }

    /// <summary>Department code (e.g. "IT-MSK-DEV").</summary>
    public string Code { get; set; } = string.Empty;
}

/// <summary>
/// City props for list examples (linked objects).
/// Used as target object for RedbListItem.Object reference.
/// </summary>
[RedbScheme("City")]
public class CityProps
{
    /// <summary>City name.</summary>
    public string Name { get; set; } = string.Empty;
    
    /// <summary>Population count.</summary>
    public int Population { get; set; }
    
    /// <summary>Region or district.</summary>
    public string Region { get; set; } = string.Empty;
    
    /// <summary>Is capital city?</summary>
    public bool IsCapital { get; set; }
    
    /// <summary>GPS coordinates [lat, lon].</summary>
    public double[] Coordinates { get; set; } = [];
}

/// <summary>
/// Person props demonstrating ListItem fields.
/// Shows single ListItem and List of ListItems usage.
/// </summary>
[RedbScheme("Person")]
public class PersonProps
{
    /// <summary>Person name.</summary>
    public string Name { get; set; } = string.Empty;
    
    /// <summary>Age in years.</summary>
    public int Age { get; set; }
    
    /// <summary>Email address.</summary>
    public string Email { get; set; } = string.Empty;
    
    /// <summary>Single ListItem field (e.g. status from dictionary).</summary>
    public RedbListItem? Status { get; set; }
    
    /// <summary>Array of ListItems (e.g. roles from dictionary).</summary>
    public List<RedbListItem>? Roles { get; set; }
}

Tree Count - CountAsync

Count tree nodes with TreeQuery.
Requires E089 to run first (creates tree data).
CountAsync on TreeQuery - counts all nodes in tree.
var sw = Stopwatch.StartNew();
var count = await redb.TreeQuery<DepartmentProps>().CountAsync();
sw.Stop();

if (count == 0)
    return Fail("E091", "Tree Count - CountAsync", ExampleTier.Free, sw.ElapsedMilliseconds, "No tree. Run E089 first.");
TreeTreeQueryCountAsyncPro
MS 5ms(404)
MS Pro 18ms(202)
PG 9ms(202)
PG Pro 10ms(202)

Tree Children - Direct

Get direct children of a node.
Uses GetChildrenAsync - returns only immediate children, not descendants.
var sw = Stopwatch.StartNew();

// Find TechCorp root - use TreeQuery for tree objects!
var roots = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code == "CORP")
    .Take(1)
    .ToListAsync();

if (roots.Count == 0)
{
    return Ok("E092", "Tree Children - Direct", ExampleTier.Free, sw.ElapsedMilliseconds, 0,
        ["No tree found. Run E090 first."]);
}

var root = (TreeRedbObject<DepartmentProps>)roots[0];

// Get direct children only
var children = await redb.GetChildrenAsync<DepartmentProps>(root);
var childList = children.ToList();
sw.Stop();

var names = childList.Select(c => c.Name).ToArray();
TreeGetChildrenAsyncPro
MS 22ms(10)
MS Pro 27ms(10)
PG 15ms(10)
PG Pro 17ms(10)

Tree Path - Breadcrumbs

Get path from node to root.
Builds breadcrumbs: Team > Department > Office > TechCorp.
var sw = Stopwatch.StartNew();

// Find deepest node (any team at level 3) - use TreeQuery!
var nodes = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code.StartsWith("TEAM-"))
    .Take(1)
    .ToListAsync();

if (nodes.Count == 0)
{
    return Ok("E093", "Tree Path - Breadcrumbs", ExampleTier.Free, sw.ElapsedMilliseconds, 0,
        ["No tree found. Run E088 or E089 first."]);
}

var node = (TreeRedbObject<DepartmentProps>)nodes[0];

// Get path to root (returns: DevAlpha, IT-MSK, Moscow, TechCorp)
var path = await redb.GetPathToRootAsync<DepartmentProps>(node);
var pathList = path.ToList();
sw.Stop();

var breadcrumbs = string.Join(" > ", pathList.Select(n => n.Name));
TreeGetPathToRootAsyncBreadcrumbsPro
MS 31ms(4)
MS Pro 109ms(4)
PG 25ms(4)
PG Pro 43ms(4)

Tree Descendants - All

Get all descendants of a node.
Returns all children, grandchildren, etc. recursively.
var sw = Stopwatch.StartNew();

// Find TechCorp root - use TreeQuery!
var roots = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code == "CORP")
    .Take(1)
    .ToListAsync();

if (roots.Count == 0)
{
    return Ok("E094", "Tree Descendants - All", ExampleTier.Free, sw.ElapsedMilliseconds, 0,
        ["No tree found. Run E090 first."]);
}

var root = (TreeRedbObject<DepartmentProps>)roots[0];

// Get ALL descendants (children, grandchildren, etc.)
var descendants = await redb.GetDescendantsAsync<DepartmentProps>(root);
var list = descendants.ToList();
sw.Stop();

// Group by level
var byLevel = list.GroupBy(d => d.Level).OrderBy(g => g.Key).ToList();
var output = byLevel.Select(g => $"Level {g.Key}: {string.Join(", ", g.Select(d => d.Props.Code))}").ToList();
output.Insert(0, $"Root: {root.Name}, Total descendants: {list.Count}");
TreeGetDescendantsAsyncRecursivePro
MS 333ms(100)
MS Pro 436ms(100)
PG 209ms(100)
PG Pro 247ms(100)

Tree Move - Relocate Node

Move node to new parent.
Demonstrates MoveObjectAsync - moves entire subtree.
var sw = Stopwatch.StartNew();

// Find a department to move - use TreeQuery!
var nodes = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code.StartsWith("DEPT-01-"))
    .Take(1)
    .ToListAsync();

if (nodes.Count == 0)
{
    return Ok("E095", "Tree Move - Relocate Node", ExampleTier.Free, sw.ElapsedMilliseconds, 0,
        ["No tree found. Run E088 or E089 first."]);
}

// Find another office as new parent - use TreeQuery!
var officeNodes = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code == "OFF-02")
    .Take(1)
    .ToListAsync();

if (officeNodes.Count == 0)
{
    return Ok("E095", "Tree Move - Relocate Node", ExampleTier.Free, sw.ElapsedMilliseconds, 0,
        ["Target office not found."]);
}

var dept = (TreeRedbObject<DepartmentProps>)nodes[0];
var targetOffice = (TreeRedbObject<DepartmentProps>)officeNodes[0];
var originalParentId = dept.parent_id;

// Move department to another office
await redb.MoveObjectAsync(dept, targetOffice);

// Move back to original parent
if (originalParentId.HasValue)
{
    var originalParent = await redb.TreeQuery<DepartmentProps>()
        .Where(d => d.Code == "OFF-01")
        .Take(1)
        .ToListAsync();

    if (originalParent.Count > 0)
    {
        var origOffice = (TreeRedbObject<DepartmentProps>)originalParent[0];
        await redb.MoveObjectAsync(dept, origOffice);
    }
}

sw.Stop();
TreeMoveObjectAsyncPro
MS 54ms(1)
MS Pro 311ms(1)
PG 41ms(1)
PG Pro 46ms(1)

Tree Query - LINQ on Trees

LINQ queries on tree structures.
TreeQuery combines tree traversal with Where/OrderBy/Take.
var sw = Stopwatch.StartNew();

// TreeQuery: find all IT departments
var itDepts = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Name.Contains("IT"))
    .OrderBy(d => d.Name)
    .ToListAsync();

// var sql = await redb.TreeQuery<DepartmentProps>()
//     .Where(d => d.Name.Contains("IT"))
//     .ToSqlStringAsync();
// Console.WriteLine(sql);

sw.Stop();

var names = itDepts.Select(d => $"{d.Name} ({d.Props.Code})").ToArray();
TreeTreeQueryWhereOrderByPro
MS 69ms(40)
MS Pro 60ms(20)
PG 16ms(20)
PG Pro 32ms(20)

Tree Query - Roots Only

Find root nodes in tree.
WhereRoots returns only top-level nodes (parent_id = null).
var sw = Stopwatch.StartNew();

// Find all root nodes
var roots = await redb.TreeQuery<DepartmentProps>()
    .WhereRoots()
    .ToListAsync();

sw.Stop();

var names = roots.Select(r => $"{r.Name} ({r.Props.Code})").ToArray();
TreeTreeQueryWhereRootsProITreeQueryable.WhereRootsIRedbService.TreeQuery
MS 11ms(4)
MS Pro 28ms(2)
PG 6ms(2)
PG Pro 6ms(2)

Tree Query - Leaves Only

Find leaf nodes in tree.
WhereLeaves returns nodes with no children.
var sw = Stopwatch.StartNew();

// Find all leaf nodes (no children)
var leaves = await redb.TreeQuery<DepartmentProps>()
    .WhereLeaves()
    .ToListAsync();

sw.Stop();

var names = leaves.Select(l => $"{l.Name} ({l.Props.Code})").ToArray();
TreeTreeQueryWhereLeavesPro
MS 371ms(320)
MS Pro 22ms(160)
PG 77ms(160)
PG Pro 12ms(160)

Tree Query - By Level

Filter tree nodes by level.
WhereLevel finds nodes at specific depth from root.
var sw = Stopwatch.StartNew();

// Find root first - use TreeQuery!
var roots = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code == "CORP")
    .Take(1)
    .ToListAsync();

if (roots.Count == 0)
{
    return Ok("E099", "Tree Query - By Level", ExampleTier.Free, sw.ElapsedMilliseconds, 0,
        ["No tree found. Run E090 first."]);
}

var rootId = roots[0].Id;

var query = redb.TreeQuery<DepartmentProps>(rootId, maxDepth: 5)
    .WhereLevel(2);

//var sql = query.ToSqlString();
//Console.WriteLine(sql);

// Find nodes at level 2 (departments under offices)
var level2 = await query
    .WhereLevel(2)
    .ToListAsync();

sw.Stop();

var names = level2.Select(n => $"{n.Name} ({n.Props.Code})").ToArray();
TreeTreeQueryWhereLevelPro
MS 72ms(50)
MS Pro 33ms(50)
PG 52ms(95)
PG Pro 19ms(50)

Tree Traversal - DFS

Depth-First traversal of tree.
Visits nodes: Root -> Child1 -> Grandchild1 -> Grandchild2 -> Child2...
Key method:
  • tree.DepthFirstTraversal() - iterate nodes depth-first
// Find root
var roots = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code == "CORP")
    .Take(1)
    .ToListAsync();

if (roots.Count == 0)
    return Fail("E100", "Tree Traversal - DFS", ExampleTier.Free, 0, "No tree. Run E088 first.");

var root = (TreeRedbObject<DepartmentProps>)roots[0];

// Load full tree with Children populated
var tree = await redb.LoadTreeAsync<DepartmentProps>(root, maxDepth: 5);

// Measure DFS traversal (cast to interface for extension method)
var sw = Stopwatch.StartNew();
var visited = ((ITreeRedbObject<DepartmentProps>)tree).DepthFirstTraversal().ToList();
sw.Stop();

var sample = visited.Take(5).Select(n => n.Props.Code).ToArray();
TreeDepthFirstTraversalDFSPro
MS 0ms(101)
MS Pro 1ms(101)
PG 1ms(96)
PG Pro 1ms(101)