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 Traversal - BFS

Breadth-First traversal of tree.
Visits nodes level by level: Root -> All Level1 -> All Level2...
Key method:
  • tree.BreadthFirstTraversal() - iterate nodes breadth-first
// Find root
var roots = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code == "CORP")
    .Take(1)
    .ToListAsync();

if (roots.Count == 0)
    return Fail("E101", "Tree Traversal - BFS", 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 BFS traversal (cast to interface for extension method)
var sw = Stopwatch.StartNew();
var visited = ((ITreeRedbObject<DepartmentProps>)tree).BreadthFirstTraversal().ToList();
sw.Stop();

// Group by level
var byLevel = visited.GroupBy(n => n.Level).OrderBy(g => g.Key);
var levelCounts = byLevel.Select(g => $"L{g.Key}:{g.Count()}").ToArray();
TreeBreadthFirstTraversalBFSPro
MS 0ms(101)
MS Pro 1ms(101)
PG 1ms(96)
PG Pro 1ms(101)

Tree - IsDescendantOf

Check if node is descendant of another.
IsDescendantOfAsync - optimized check without loading full tree.
// Find root and a deep node
var roots = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code == "CORP")
    .Take(1)
    .ToListAsync();

var teams = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code.StartsWith("TEAM-"))
    .Take(1)
    .ToListAsync();

if (roots.Count == 0 || teams.Count == 0)
    return Fail("E102", "Tree - IsDescendantOf", ExampleTier.Free, 0, "No tree. Run E088 first.");

var root = roots[0];
var team = teams[0];

// Check if team is descendant of root
var sw = Stopwatch.StartNew();
var isDescendant = await team.IsDescendantOfAsync<DepartmentProps>(root, redb);
var isNotDescendant = await root.IsDescendantOfAsync<DepartmentProps>(team, redb);
sw.Stop();
TreeIsDescendantOfAsyncPro
MS 30ms(2)
MS Pro 57ms(2)
PG 20ms(2)
PG Pro 38ms(2)

Tree - IsAncestorOf

Check if node is ancestor of another.
IsAncestorOfAsync - checks if this node is parent/grandparent of target.
// Find root and a deep node
var roots = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code == "CORP")
    .Take(1)
    .ToListAsync();

var teams = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code.StartsWith("TEAM-"))
    .Take(1)
    .ToListAsync();

if (roots.Count == 0 || teams.Count == 0)
    return Fail("E103", "Tree - IsAncestorOf", ExampleTier.Free, 0, "No tree. Run E088 first.");

var root = roots[0];
var team = teams[0];

// Check if root is ancestor of team
var sw = Stopwatch.StartNew();
var isAncestor = await root.IsAncestorOfAsync<DepartmentProps>(team, redb);
var isNotAncestor = await team.IsAncestorOfAsync<DepartmentProps>(root, redb);
sw.Stop();
TreeIsAncestorOfAsyncPro
MS 27ms(2)
MS Pro 60ms(2)
PG 20ms(2)
PG Pro 38ms(2)

Tree - GetLevel

Get tree level of a node.
GetTreeLevelAsync - counts levels from root (root = 0).
// Find nodes at different levels
var roots = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code == "CORP")
    .Take(1)
    .ToListAsync();

var offices = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code == "OFF-01")
    .Take(1)
    .ToListAsync();

var teams = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code.StartsWith("TEAM-"))
    .Take(1)
    .ToListAsync();

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

var sw = Stopwatch.StartNew();
var rootLevel = await roots[0].GetTreeLevelAsync<DepartmentProps>(redb);
var officeLevel = offices.Count > 0 ? await offices[0].GetTreeLevelAsync<DepartmentProps>(redb) : -1;
var teamLevel = teams.Count > 0 ? await teams[0].GetTreeLevelAsync<DepartmentProps>(redb) : -1;
sw.Stop();
TreeGetTreeLevelAsyncPro
MS 40ms(3)
MS Pro 78ms(3)
PG 26ms(3)
PG Pro 54ms(3)

Tree Query - Scoped to Root

TreeQuery scoped to specific root.
TreeQuery(rootId, maxDepth) - queries only within subtree.
// Find an office to use as root
var offices = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code == "OFF-01")
    .Take(1)
    .ToListAsync();

if (offices.Count == 0)
    return Fail("E105", "Tree Query - Scoped to Root", ExampleTier.Free, 0, "No tree. Run E088 first.");

var officeId = offices[0].Id;

// Query only within this office's subtree
var sw = Stopwatch.StartNew();
var subtreeNodes = await redb.TreeQuery<DepartmentProps>(officeId, maxDepth: 3)
    .ToListAsync();
sw.Stop();

var codes = subtreeNodes.Take(5).Select(n => n.Props.Code).ToArray();
TreeTreeQueryRootIdPro
MS 31ms(25)
MS Pro 19ms(25)
PG 19ms(30)
PG Pro 7ms(25)

Tree Query - WhereChildrenOf

Query direct children of a node.
WhereChildrenOf(parentId) - returns only immediate children.
// Find root
var roots = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code == "CORP")
    .Take(1)
    .ToListAsync();

if (roots.Count == 0)
    return Fail("E106", "Tree Query - WhereChildrenOf", ExampleTier.Free, 0, "No tree. Run E088 first.");

var rootId = roots[0].Id;

// Get direct children only
var sw = Stopwatch.StartNew();
var children = await redb.TreeQuery<DepartmentProps>()
    .WhereChildrenOf(rootId)
    .ToListAsync();
sw.Stop();

var names = children.Take(5).Select(c => c.Props.Code).ToArray();
TreeTreeQueryWhereChildrenOfPro
MS 15ms(10)
MS Pro 9ms(10)
PG 9ms(10)
PG Pro 7ms(10)

Tree Query - Multiple Roots

TreeQuery with multiple root parents.
TreeQuery(parents[], maxDepth) - queries across multiple subtrees.
// Find two offices to use as roots
var office1 = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code == "OFF-01")
    .Take(1)
    .ToListAsync();

var office2 = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code == "OFF-02")
    .Take(1)
    .ToListAsync();

if (office1.Count == 0 || office2.Count == 0)
    return Fail("E107", "Tree Query - Multiple Roots", ExampleTier.Free, 0, "No tree. Run E088 first.");

var parents = new IRedbObject[] { office1[0], office2[0] };

// Query across both subtrees
var sw = Stopwatch.StartNew();
var results = await redb.TreeQuery<DepartmentProps>(parents, maxDepth: 3)
    .ToListAsync();
sw.Stop();

var byParent = results.GroupBy(r => r.ParentId).Select(g => $"{g.Key}:{g.Count()}").ToArray();
TreeTreeQueryMultiRootPro
MS 56ms(50)
MS Pro 14ms(50)
PG 32ms(55)
PG Pro 8ms(50)

Tree Query - ToTreeListAsync

ToTreeListAsync with Parent chain.
Returns nodes with Parent property populated up to root.
// Query teams (deep nodes)
var sw = Stopwatch.StartNew();
var teams = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code.StartsWith("TEAM-"))
    .Take(5)
    .ToTreeListAsync();
sw.Stop();

if (teams.Count == 0)
    return Fail("E108", "Tree Query - ToTreeListAsync", ExampleTier.Free, sw.ElapsedMilliseconds, "No tree. Run E088 first.");

// Check parent chain
var first = teams[0];
var parentDepth = 0;
var current = first.Parent;
while (current != null && parentDepth < 10)
{
    parentDepth++;
    current = (current as TreeRedbObject<DepartmentProps>)?.Parent;
}
TreeToTreeListAsyncParentChainPro
MS 22ms(5)
MS Pro 89ms(5)
PG 25ms(5)
PG Pro 87ms(5)

Tree Query - ToRootListAsync

ToRootListAsync - get full tree structure.
Returns root nodes with Children populated recursively.
// Get full tree from roots
var sw = Stopwatch.StartNew();
var rootTrees = await redb.TreeQuery<DepartmentProps>()
    .WhereRoots()
    .ToRootListAsync();
sw.Stop();

if (rootTrees.Count == 0)
    return Fail("E109", "Tree Query - ToRootListAsync", ExampleTier.Free, sw.ElapsedMilliseconds, "No tree. Run E088 first.");

// Count total nodes in tree
var totalNodes = CountNodes(rootTrees[0]);
CountNodes
private static int CountNodes(ITreeRedbObject node)
    {
        var count = 1;
        foreach (var child in node.Children)
            count += CountNodes(child);
        return count;
    }
TreeToRootListAsyncFullTreePro
MS 14ms(1)
MS Pro 25ms(1)
PG 10ms(1)
PG Pro 14ms(1)

Tree Query - WhereHasAncestor

WhereHasAncestor - polymorphic ancestor filter.
Find nodes that have a specific type of ancestor matching condition.
// Find teams that have an ancestor with Budget > 500000 (decimal test!)
var sw = Stopwatch.StartNew();
var teams = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code.StartsWith("TEAM-"))
    .WhereHasAncestor<DepartmentProps>(anc => anc.Budget > 500000m)
    .ToListAsync();
sw.Stop();

var codes = teams.Take(5).Select(t => t.Props.Code).ToArray();
TreeWhereHasAncestorPolymorphicProITreeQueryable.WhereHasAncestor
MS 1837ms(160)
MS Pro 95ms(200)
PG 69ms(240)
PG Pro 114ms(200)