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

ListItem - WhereIn by Value

Query filtering by ListItem.Value using WhereIn.
Shows how to filter objects by multiple ListItem values at once.
Requires E114-E118 to run first.
var sw = Stopwatch.StartNew();

// Query persons where Status.Value in ["Active", "Pending"]
var targetValues = new[] { "Active", "Pending", "Blocked" };
var query = redb.Query<PersonProps>()
    .WhereIn(p => p.Status!.Value, targetValues)
    .Take(100);

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

var results = await query.ToListAsync();

sw.Stop();

if (results.Count == 0)
{
    return Ok("E121", "ListItem - WhereIn by Value", ExampleTier.Free, sw.ElapsedMilliseconds, 0,
        [$"Filter: Status.Value IN [{string.Join(", ", targetValues)}]", "No matching persons found"]);
}

var statuses = results.Select(r => r.Props?.Status?.Value ?? "N/A").Distinct();
ListItemWhereInValueQueryIRedbQueryable.WhereInRedbListItem.Value
MS 10ms(2)
MS Pro 56ms(1)
PG 8ms(1)
PG Pro 9ms(1)

ListItem - Direct Compare

Query filtering by direct ListItem comparison.
Shows how to compare ListItem field with a ListItem instance directly.
Requires E114-E118 to run first.
var sw = Stopwatch.StartNew();

// Get a ListItem to compare against
var list = await redb.ListProvider.GetListByNameAsync("ExampleStatuses");
if (list == null)
{
    sw.Stop();
    return Fail("E122", "ListItem - Direct Compare", ExampleTier.Free, sw.ElapsedMilliseconds,
        "List 'ExampleStatuses' not found. Run E114 first.");
}

var items = await redb.ListProvider.GetListItemsAsync(list.Id);
var activeItem = items.FirstOrDefault(i => i.Value == "Active");
if (activeItem == null)
{
    sw.Stop();
    return Fail("E122", "ListItem - Direct Compare", ExampleTier.Free, sw.ElapsedMilliseconds,
        "Item 'Active' not found. Run E115 first.");
}

// Query persons where Status == activeItem (by ID)
var query = redb.Query<PersonProps>()
    .Where(p => p.Status == activeItem)
    .Take(100);

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

var results = await query.ToListAsync();

sw.Stop();
ListItemWhereCompareQueryIRedbQueryable.WhereRedbListItem
MS 15ms(2)
MS Pro 34ms(1)
PG 7ms(1)
PG Pro 11ms(1)

ListItem Array - Any

Query filtering by ListItem array using Any().
Shows how to filter objects where any element in ListItem array matches condition.
Requires E114-E119 to run first.
var sw = Stopwatch.StartNew();

// Query persons where any Role has Value == "Active"
var query = redb.Query<PersonProps>()
    .Where(p => p.Roles!.Any(r => r.Value == "Active"))
    .Take(100);

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

var results = await query.ToListAsync();

sw.Stop();

if (results.Count == 0)
{
    return Ok("E123", "ListItem Array - Any", ExampleTier.Free, sw.ElapsedMilliseconds, 0,
        ["Filter: Roles.Any(r => r.Value == 'Active')", "No matching persons found. Run E119 first."]);
}

var firstName = results.FirstOrDefault()?.Props?.Name ?? "N/A";
var rolesCount = results.FirstOrDefault()?.Props?.Roles?.Count ?? 0;
ListItemArrayAnyQueryIRedbQueryable.WhereList<RedbListItem>.Any
MS 11ms(2)
MS Pro 57ms(1)
PG 10ms(1)
PG Pro 10ms(1)

SumAsync - Total

Calculates sum of a numeric field using SumAsync.
Server-side aggregation without loading objects.
var sw = Stopwatch.StartNew();

var query = redb.Query<EmployeeProps>();

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

var totalSalary = await query.SumAsync(e => e.Salary);

sw.Stop();
SumAggregationAnalyticsIRedbQueryable.SumAsync
MS 12ms(1)
MS Pro 37ms(1)
PG 28ms(1)
PG Pro 33ms(1)

AverageAsync - Mean

Calculates average of a numeric field using AverageAsync.
Server-side aggregation without loading objects.
var sw = Stopwatch.StartNew();

var query = redb.Query<EmployeeProps>();

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

var avgAge = await query.AverageAsync(e => e.Age);

sw.Stop();
AverageAvgAggregationAnalyticsIRedbQueryable.AverageAsync
MS 7ms(1)
MS Pro 26ms(1)
PG 22ms(1)
PG Pro 27ms(1)

MinAsync/MaxAsync - Range

Calculates min and max of numeric fields using MinAsync/MaxAsync.
Server-side aggregation without loading objects.
var sw = Stopwatch.StartNew();

var query = redb.Query<EmployeeProps>();

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

var minSalary = await query.MinAsync(e => e.Salary);
var maxSalary = await query.MaxAsync(e => e.Salary);

sw.Stop();
MinMaxAggregationAnalyticsIRedbQueryable.MinAsyncIRedbQueryable.MaxAsync
MS 23ms(2)
MS Pro 71ms(2)
PG 45ms(2)
PG Pro 58ms(2)

AggregateAsync - Batch

Batch aggregation with multiple functions in single query.
Calculates Sum, Avg, Min, Max, Count in ONE SQL request.
var sw = Stopwatch.StartNew();

// Multiple aggregations in ONE query (Pro PVT-based)
var stats = await redb.Query<EmployeeProps>()
    .AggregateAsync(x => new
    {
        TotalSalary = Agg.Sum(x.Props.Salary),
        AvgAge = Agg.Average(x.Props.Age),
        MinSalary = Agg.Min(x.Props.Salary),
        MaxSalary = Agg.Max(x.Props.Salary),
        Count = Agg.Count()
    });

sw.Stop();
AggregateBatchSumAvgCountIRedbQueryable.AggregateAsyncAgg.SumAgg.AverageAgg.Count
MS 147ms(5588)
MS Pro 117ms(5083)
PG 46ms(13753)
PG Pro 45ms(13955)

GroupBy - Simple

Groups objects by a field and calculates aggregates per group.
SQL: GROUP BY Department with SUM, AVG, COUNT.
var sw = Stopwatch.StartNew();

// Uncomment to see generated SQL:
// var sql = await redb.Query<EmployeeProps>()
//     .GroupBy(x => x.Department)
//     .ToSqlStringAsync(g => new { Dept = g.Key, Total = Agg.Sum(g, x => x.Salary) });
// Console.WriteLine(sql);

var byDept = await redb.Query<EmployeeProps>()
    .GroupBy(x => x.Department)
    .SelectAsync(g => new
    {
        Department = g.Key,
        TotalSalary = Agg.Sum(g, x => x.Salary),
        AvgAge = Agg.Average(g, x => x.Age),
        Count = Agg.Count(g)
    });

sw.Stop();

var first = byDept.FirstOrDefault();
GroupByAggregationAnalyticsIRedbQueryable.GroupByIGroupedQueryable.SelectAsync
MS 52ms(6)
MS Pro 153ms(6)
PG 128ms(6)
PG Pro 65ms(6)

GroupBy - With Filter

GroupBy with Where filter applied before grouping.
Filter employees by salary, then group by department.
var sw = Stopwatch.StartNew();

// Uncomment to see generated SQL:
//var sql = await redb.Query<EmployeeProps>()
//    .Where(x => x.Salary > 50000)
//    .GroupBy(x => x.Department)
//    .ToSqlStringAsync(g => new { Dept = g.Key, Count = Agg.Count(g) });
//Console.WriteLine(sql);

var byDeptFiltered = await redb.Query<EmployeeProps>()
    .Where(x => x.Salary > 50000m)
    .GroupBy(x => x.Department)
    .SelectAsync(g => new
    {
        Department = g.Key,
        TotalSalary = Agg.Sum(g, x => x.Salary),
        Count = Agg.Count(g)
    });

sw.Stop();

var first = byDeptFiltered.FirstOrDefault();
GroupByWhereFilterAnalyticsIRedbQueryable.GroupByIRedbQueryable.Where
MS 89ms(5)
MS Pro 563ms(5)
PG 188ms(5)
PG Pro 43ms(5)

GroupBy - Composite Key

GroupBy with composite key (multiple fields).
Group by Department AND Position for detailed breakdown.
var sw = Stopwatch.StartNew();

// Uncomment to see generated SQL:
// var sql = await redb.Query<EmployeeProps>()
//     .GroupBy(x => new { x.Department, x.Position })
//     .ToSqlStringAsync(g => new { g.Key.Department, g.Key.Position, Count = Agg.Count(g) });
// Console.WriteLine(sql);

var byDeptPosition = await redb.Query<EmployeeProps>()
    .GroupBy(x => new { x.Department, x.Position })
    .SelectAsync(g => new
    {
        g.Key.Department,
        g.Key.Position,
        TotalSalary = Agg.Sum(g, x => x.Salary),
        Count = Agg.Count(g)
    });

sw.Stop();

var first = byDeptPosition.FirstOrDefault();
GroupByCompositeMultiKeyAnalyticsIRedbQueryable.GroupBy
MS 5377ms(6)
MS Pro 158ms(6)
PG 91ms(7)
PG Pro 57ms(7)