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; }
}

Scalar + Array Combined

Demonstrates combining scalar field filter with array Contains filter.
Finds senior developers (Age > 30) who have specific skills.
Pro feature: mixed scalar and array expressions in single query.
var sw = Stopwatch.StartNew();

// Find senior developers: Age > 30 AND has C# skill
var query = redb.Query<EmployeeProps>()
    .Where(e => e.Age > 30 && e.Skills != null && e.Skills.Contains("C#"))
    .Take(100);

// Uncomment to see generated SQL:
// var sql = await query.ToSqlStringAsync();
// Console.WriteLine(sql);

var results = await query.ToListAsync();
var totalCount = await redb.Query<EmployeeProps>()
    .Where(e => e.Age > 30 && e.Skills != null && e.Skills.Contains("C#"))
    .CountAsync();

sw.Stop();

var avgAge = results.Any() ? results.Average(e => e.Props.Age) : 0;
var sample = results.FirstOrDefault();
ArrayScalarCombinedIRedbQueryable.WhereArray.Contains
MS 1459ms(810)
MS Pro 232ms(735)
PG 762ms(2010)
PG Pro 138ms(2040)

String.Length Filter

Demonstrates String.Length property in Where clause.
Server-side: LENGTH() in PostgreSQL, LEN() in MSSQL.
Pro feature: string property access in expressions.
var sw = Stopwatch.StartNew();

// Find employees with long last names (> 6 characters)
var query = redb.Query<EmployeeProps>()
    .Where(e => e.LastName.Length > 6)
    .Take(100);

// Uncomment to see generated SQL (contains LENGTH or LEN):
// var sql = await query.ToSqlStringAsync();
// Console.WriteLine(sql);

var results = await query.ToListAsync();
var totalCount = await redb.Query<EmployeeProps>()
    .Where(e => e.LastName.Length > 6)
    .CountAsync();

sw.Stop();

var names = results.Take(5)
    .Select(e => $"{e.Props.LastName} ({e.Props.LastName.Length} chars)");
StringLengthPropertyIRedbQueryable.WhereString.Length
MS 1365ms(4913)
MS Pro 122ms(4458)
PG 611ms(12191)
PG Pro 85ms(12373)

TreeQuery - GroupBy

Demonstrates GroupBy aggregation on TreeQuery.
Groups tree nodes and calculates aggregates (SUM, COUNT) within tree context.
Pro feature: TreeQuery + GroupBy for hierarchical data analysis.
var sw = Stopwatch.StartNew();

// Ensure tree data exists (from E089_TreeCreate)
var root = await redb.TreeQuery<DepartmentProps>().WhereRoots().FirstOrDefaultAsync();
if (root == null)
{
    sw.Stop();
    return Fail("E173", "TreeQuery - GroupBy", ExampleTier.Free, sw.ElapsedMilliseconds,
        "No tree data found. Please run E089_TreeCreate first.");
}

// Group departments by IsActive status and aggregate budget
var groupedQuery = redb.TreeQuery<DepartmentProps>(root.Id)
    .Where(d => d.Budget > 0)
    .GroupBy(d => d.IsActive);

// Uncomment to see generated SQL:
// var sql = await groupedQuery.ToSqlStringAsync(g => new { 
//     IsActive = g.Key, 
//     TotalBudget = Agg.Sum(g, d => d.Budget),
//     Count = Agg.Count(g)
// });
// Console.WriteLine(sql);

var results = await groupedQuery.SelectAsync(g => new
{
    IsActive = g.Key,
    TotalBudget = Agg.Sum(g, d => d.Budget),
    DeptCount = Agg.Count(g)
});

sw.Stop();

var output = results.Select(r => 
    $"Active={r.IsActive}: {r.DeptCount} depts, Budget=${r.TotalBudget:N0}").ToArray();
TreeGroupByAggregationITreeQueryable.GroupByAgg.SumAgg.Count
MS 125ms(1)
MS Pro 40ms(1)
PG 73ms(1)
PG Pro 22ms(1)

TreeQuery - Window Functions

Demonstrates Window Functions on TreeQuery.
Calculates ROW_NUMBER and running totals within tree hierarchy.
Pro feature: TreeQuery + Window for hierarchical rankings and cumulative values.
var sw = Stopwatch.StartNew();

// Ensure tree data exists (from E089_TreeCreate)
var root = await redb.TreeQuery<DepartmentProps>().WhereRoots().FirstOrDefaultAsync();
if (root == null)
{
    sw.Stop();
    return Fail("E174", "TreeQuery - Window Functions", ExampleTier.Free, sw.ElapsedMilliseconds,
        "No tree data found. Please run E089_TreeCreate first.");
}

// Window functions on tree: rank departments by budget within the hierarchy
var windowQuery = redb.TreeQuery<DepartmentProps>(root.Id)
    .Where(d => d.Budget > 0)
    .Take(20)
    .WithWindow(w => w
        .PartitionBy(d => d.IsActive)
        .OrderByDesc(d => d.Budget));

// Uncomment to see generated SQL:
// var sql = await windowQuery.ToSqlStringAsync(d => new {
//     d.Props.Name,
//     d.Props.Budget,
//     Rank = Win.RowNumber(),
//     RunningBudget = Win.Sum(d.Props.Budget)
// });
// Console.WriteLine(sql);

var results = await windowQuery.SelectAsync(d => new
{
    Name = d.Props.Name,
    Budget = d.Props.Budget,
    IsActive = d.Props.IsActive,
    Rank = Win.RowNumber(),
    RunningBudget = Win.Sum(d.Props.Budget)
});

sw.Stop();

var output = results.Take(5).Select(r => 
    $"#{r.Rank} {r.Name}: ${r.Budget:N0} (Running: ${r.RunningBudget:N0})").ToArray();
TreeWindowRowNumberRunningSumITreeQueryable.WithWindowWin.RowNumberWin.Sum
MS 45ms(20)
MS Pro 52ms(100)
PG 34ms(20)
PG Pro 24ms(100)

TreeQuery - GroupBy + Window

Demonstrates GroupBy + Window Functions on TreeQuery.
First groups tree nodes, then applies window functions to rank the groups.
Pro feature: TreeQuery + GroupBy + Window for advanced hierarchical analytics.
var sw = Stopwatch.StartNew();

// Ensure tree data exists (from E089_TreeCreate)
var root = await redb.TreeQuery<DepartmentProps>().WhereRoots().FirstOrDefaultAsync();
if (root == null)
{
    sw.Stop();
    return Fail("E175", "TreeQuery - GroupBy + Window", ExampleTier.Free, sw.ElapsedMilliseconds,
        "No tree data found. Please run E089_TreeCreate first.");
}

// GroupBy + Window: group by IsActive, then rank groups by total budget
var groupedWindowQuery = redb.TreeQuery<DepartmentProps>(root.Id)
    .Where(d => d.Budget > 0)
    .GroupBy(d => d.IsActive)
    .WithWindow(w => w
        .OrderByDesc(g => Agg.Sum(g, d => d.Budget)));

// Uncomment to see generated SQL:
// var sql = await groupedWindowQuery.ToSqlStringAsync(g => new {
//     IsActive = g.Key,
//     TotalBudget = Agg.Sum(g, d => d.Budget),
//     DeptCount = Agg.Count(g),
//     Rank = Win.RowNumber()
// });
// Console.WriteLine(sql);

var results = await groupedWindowQuery.SelectAsync(g => new
{
    IsActive = g.Key,
    TotalBudget = Agg.Sum(g, d => d.Budget),
    DeptCount = Agg.Count(g),
    Rank = Win.RowNumber()
});

sw.Stop();

var output = results.Select(r => 
    $"#{r.Rank} Active={r.IsActive}: {r.DeptCount} depts, Total=${r.TotalBudget:N0}").ToArray();
TreeGroupByWindowCombinedITreeQueryable.GroupByIGroupedQueryable.WithWindowWin.RowNumber
MS Pro 43ms(1)
PG Pro 22ms(1)

TreeQuery - DistinctBy

Demonstrates DistinctBy on TreeQuery to get unique tree nodes by a Props field.
Useful for removing duplicates based on specific property values.
Pro feature: DistinctBy with tree context.
var sw = Stopwatch.StartNew();

// Ensure tree data exists (from E089_TreeCreate)
var root = await redb.TreeQuery<DepartmentProps>().WhereRoots().FirstOrDefaultAsync();
if (root == null)
{
    sw.Stop();
    return Fail("E176", "TreeQuery - DistinctBy", ExampleTier.Free, sw.ElapsedMilliseconds,
        "No tree data found. Please run E089_TreeCreate first.");
}

// Get total count before distinct
var totalCount = await redb.TreeQuery<DepartmentProps>(root.Id).CountAsync();

// Get unique departments by IsActive status (will return max 2: true and false)
var query = redb.TreeQuery<DepartmentProps>(root.Id)
    .DistinctBy(d => d.IsActive)
    .Take(100);

// Uncomment to see generated SQL:
//var sql = query.ToSqlString();
//Console.WriteLine(sql);

var uniqueByStatus = await query.ToListAsync();

sw.Stop();

var statuses = uniqueByStatus.Select(d => $"IsActive={d.Props.IsActive}");
TreeDistinctByUniqueITreeQueryable.DistinctBy
MS Pro 56ms(1)
PG Pro 24ms(1)

TreeQuery - DistinctByRedb

Demonstrates DistinctByRedb on TreeQuery to get unique tree nodes by a base field.
Uses _objects table fields directly (no EAV join) - highly optimized.
Pro feature: DistinctByRedb with tree context.
var sw = Stopwatch.StartNew();

// Ensure tree data exists (from E089_TreeCreate)
var root = await redb.TreeQuery<DepartmentProps>().WhereRoots().FirstOrDefaultAsync();
if (root == null)
{
    sw.Stop();
    return Fail("E177", "TreeQuery - DistinctByRedb", ExampleTier.Free, sw.ElapsedMilliseconds,
        "No tree data found. Please run E089_TreeCreate first.");
}

// Get total count before distinct
var totalCount = await redb.TreeQuery<DepartmentProps>(root.Id).CountAsync();

// Get unique departments by ParentId (base field) - shows unique parent branches
var query = redb.TreeQuery<DepartmentProps>(root.Id)
    .DistinctByRedb(d => d.ParentId)
    .Take(20);

// Uncomment to see generated SQL (no _values JOIN):
// var sql = query.ToSqlString();
// Console.WriteLine(sql);

var uniqueByParent = await query.ToListAsync();

sw.Stop();

var parentIds = uniqueByParent.Take(5).Select(d => d.parent_id?.ToString() ?? "null");
TreeDistinctByRedbBaseFieldITreeQueryable.DistinctByRedb
MS Pro 29ms(20)
PG Pro 18ms(20)

TreeQuery - OrderBy

Demonstrates OrderBy on TreeQuery to sort tree nodes by a Props field.
Ascending order by department Code.
Pro feature: OrderBy with tree context.
var sw = Stopwatch.StartNew();

// Ensure tree data exists (from E089_TreeCreate)
var root = await redb.TreeQuery<DepartmentProps>().WhereRoots().FirstOrDefaultAsync();
if (root == null)
{
    sw.Stop();
    return Fail("E178", "TreeQuery - OrderBy", ExampleTier.Free, sw.ElapsedMilliseconds,
        "No tree data found. Please run E089_TreeCreate first.");
}

// Sort departments by Code (ascending)
var query = redb.TreeQuery<DepartmentProps>(root.Id)
    .OrderBy(d => d.Code)
    .Take(100);

// Uncomment to see generated SQL:
// var sql = query.ToSqlString();
// Console.WriteLine(sql);

var sorted = await query.ToListAsync();

sw.Stop();

var codes = sorted.Take(5).Select(d => d.Props.Code);
TreeOrderBySortAscendingITreeQueryable.OrderBy
MS 130ms(100)
MS Pro 54ms(100)
PG 60ms(100)
PG Pro 24ms(100)

TreeQuery - OrderByDescending

Demonstrates OrderByDescending on TreeQuery to sort tree nodes in reverse order.
Descending order by Budget - highest budgets first.
Pro feature: OrderByDescending with tree context.
var sw = Stopwatch.StartNew();

// Ensure tree data exists (from E089_TreeCreate)
var root = await redb.TreeQuery<DepartmentProps>().WhereRoots().FirstOrDefaultAsync();
if (root == null)
{
    sw.Stop();
    return Fail("E179", "TreeQuery - OrderByDescending", ExampleTier.Free, sw.ElapsedMilliseconds,
        "No tree data found. Please run E089_TreeCreate first.");
}

// Sort departments by Budget (descending) - highest first
var query = redb.TreeQuery<DepartmentProps>(root.Id)
    .Where(d => d.Budget > 0)
    .OrderByDescending(d => d.Budget)
    .Take(100);

// Uncomment to see generated SQL:
// var sql = query.ToSqlString();
// Console.WriteLine(sql);

var sorted = await query.ToListAsync();

sw.Stop();

var topBudgets = sorted.Take(5).Select(d => $"{d.Props.Name}: ${d.Props.Budget:N0}");
TreeOrderByDescendingSortDescendingITreeQueryable.OrderByDescending
MS 126ms(100)
MS Pro 71ms(100)
PG 82ms(100)
PG Pro 22ms(100)

TreeQuery - DistinctBy + OrderBy

Demonstrates combining DistinctBy and OrderByDescending on TreeQuery.
Gets unique values by one field, sorted by another.
Pro feature: chained tree query operations.
var sw = Stopwatch.StartNew();

// Ensure tree data exists (from E089_TreeCreate)
var root = await redb.TreeQuery<DepartmentProps>().WhereRoots().FirstOrDefaultAsync();
if (root == null)
{
    sw.Stop();
    return Fail("E180", "TreeQuery - DistinctBy + OrderBy", ExampleTier.Free, sw.ElapsedMilliseconds,
        "No tree data found. Please run E089_TreeCreate first.");
}

// Get unique by IsActive, then sort by Budget descending
var query = redb.TreeQuery<DepartmentProps>(root.Id)
    .Where(d => d.Budget > 0)
    .DistinctBy(d => d.IsActive)
    .OrderByDescending(d => d.Budget)
    .Take(100);

// Uncomment to see generated SQL:
//var sql = query.ToSqlString();
//Console.WriteLine(sql);

var results = await query.ToListAsync();

sw.Stop();

var output = results.Select(d => 
    $"Active={d.Props.IsActive}, Budget=${d.Props.Budget:N0}");
TreeDistinctByOrderByCombinedITreeQueryable.DistinctByITreeQueryable.OrderByDescending
MS Pro 45ms(1)
PG Pro 25ms(1)