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 Query - WhereHasDescendant

WhereHasDescendant - find parents by child criteria.
Find offices that have active departments beneath them.
// Find offices that have descendants with Budget > 100000 (decimal test!)
var sw = Stopwatch.StartNew();
var offices = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code.StartsWith("OFF-"))
    .WhereHasDescendant<DepartmentProps>(desc => desc.Budget > 100000m)
    .ToListAsync();
sw.Stop();

var codes = offices.Take(5).Select(o => o.Props.Code).ToArray();
TreeWhereHasDescendantPolymorphicPro
MS 88ms(40)
MS Pro 62ms(42)
PG 37ms(20)
PG Pro 27ms(42)

Tree - GetStats

Tree statistics via TreeCollection.
TreeCollection.GetStats() - node count, depth, leaf count, max width.
Key method:
  • collection.GetStats() - get tree metrics
// Find root
var roots = await redb.TreeQuery<DepartmentProps>()
    .Where(d => d.Code == "CORP")
    .Take(1)
    .ToListAsync();

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

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

// Load tree and build collection
var sw = Stopwatch.StartNew();
var tree = await redb.LoadTreeAsync<DepartmentProps>(root, maxDepth: 5);

// Build TreeCollection for stats
var collection = new TreeCollection<DepartmentProps>();
AddToCollection(collection, tree);

var stats = collection.GetStats();
sw.Stop();
AddToCollection
private static void AddToCollection(TreeCollection<DepartmentProps> collection, ITreeRedbObject<DepartmentProps> node)
    {
        collection.Add(node);
        foreach (var child in node.Children.OfType<ITreeRedbObject<DepartmentProps>>())
            AddToCollection(collection, child);
    }
TreeTreeCollectionGetStatsStatisticsPro
MS 331ms(101)
MS Pro 408ms(101)
PG 191ms(96)
PG Pro 280ms(101)

Tree Query - ToFlatListAsync

Load tree nodes as flat list without Parent/Children links.
ToFlatListAsync is faster than ToTreeListAsync - skips relationship building.
Requires E089 to run first (creates tree data).
var sw = Stopwatch.StartNew();

// Load root department
var root = await redb.TreeQuery<DepartmentProps>()
    .WhereRoots()
    .Take(1)
    .ToListAsync();

if (root.Count == 0)
{
    sw.Stop();
    return Fail("E113", "Tree Query - ToFlatListAsync", ExampleTier.Free, sw.ElapsedMilliseconds,
        "No tree found. Run E089 first.");
}

// Load tree as flat list (no Parent/Children links)
var query = redb.TreeQuery<DepartmentProps>(root[0].Id, maxDepth: 3)
    .Where(d => d.IsActive);

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

var flatList = await query.ToFlatListAsync();

sw.Stop();

var sample = flatList.FirstOrDefault()?.Props.Name ?? "N/A";
ToFlatListAsyncTreeFlatPerformanceITreeQueryable.ToFlatListAsync
MS 136ms(100)
MS Pro 68ms(100)
PG 56ms(105)
PG Pro 25ms(100)

List - Create

Creates a new RedbList (dictionary/lookup table).
RedbList is used to store reference data like statuses, categories, etc.
var sw = Stopwatch.StartNew();

// Check if list already exists and delete it (with FK cleanup)
var existing = await redb.ListProvider.GetListByNameAsync("ExampleStatuses");
if (existing != null)
{
    // First delete all _values referencing list items (FK constraint)
    var items = await redb.ListProvider.GetListItemsAsync(existing.Id);
    var itemIds = items.Select(i => i.Id).ToList();
    if (itemIds.Count > 0)
    {
        await redb.Context.Bulk.BulkDeleteValuesByListItemIdsAsync(itemIds);
    }
    await redb.ListProvider.DeleteListAsync(existing.Id);
}

// Create a new list (dictionary)
var statusList = RedbList.Create("ExampleStatuses", "Example Statuses");

// Uncomment to see generated SQL:
// (Lists use direct ADO.NET, no ORM query)

var savedList = await redb.ListProvider.SaveListAsync(statusList);

sw.Stop();
ListCreateDictionaryIListProvider.SaveListAsyncRedbList.Create
MS 16ms(1)
MS Pro 295ms(1)
PG 525ms(1)
PG Pro 474ms(1)

List - Add Items

Adds multiple items to a RedbList using AddItemsAsync.
Batch operation for efficient bulk insert of list items.
Requires E114 to run first (creates the list).
var sw = Stopwatch.StartNew();

// Get existing list (created in E114)
var list = await redb.ListProvider.GetListByNameAsync("ExampleStatuses");
if (list == null)
{
    sw.Stop();
    return Fail("E115", "List - Add Items", ExampleTier.Free, sw.ElapsedMilliseconds,
        "List 'ExampleStatuses' not found. Run E114 first.");
}

// Prepare values and aliases
var values = new List<string> { "Active", "Inactive", "Pending", "Blocked" };
var aliases = new List<string> { "Active status", "Inactive status", "Pending review", "Blocked access" };

// Uncomment to see generated SQL:
// (Lists use direct ADO.NET, no ORM query)

// Batch add items
var addedItems = await redb.ListProvider.AddItemsAsync(list, values, aliases);

sw.Stop();

var itemsList = string.Join(", ", addedItems.Select(i => i.Value));
ListAddItemsBatchIListProvider.AddItemsAsync
MS Pro 42ms(4)
PG 18ms(4)
PG Pro 17ms(4)

List - Get Items

Gets a RedbList by name and retrieves its items.
Shows how to lookup lists and access their contents.
Requires E114+E115 to run first.
var sw = Stopwatch.StartNew();

// Get list by name
var list = await redb.ListProvider.GetListByNameAsync("ExampleStatuses");
if (list == null)
{
    sw.Stop();
    return Fail("E116", "List - Get Items", ExampleTier.Free, sw.ElapsedMilliseconds,
        "List 'ExampleStatuses' not found. Run E114 first.");
}

// Uncomment to see generated SQL:
// (Lists use direct ADO.NET, no ORM query)

// Get all items from the list
var items = await redb.ListProvider.GetListItemsAsync(list.Id);

sw.Stop();

var itemsPreview = string.Join(", ", items.Take(3).Select(i => $"{i.Value}"));
if (items.Count > 3) itemsPreview += "...";
ListGetByNameGetItemsIListProvider.GetListByNameAsyncIListProvider.GetListItemsAsync
MS 0ms(4)
MS Pro 2ms(4)
PG 1ms(4)
PG Pro 1ms(4)

ListItem - With Object

Creates a ListItem with linked RedbObject.
ListItem can reference any object via IdObject property.
Linked object is loaded lazily via Object property.
Requires E114+E115 to run first.
var sw = Stopwatch.StartNew();

// Get existing list
var list = await redb.ListProvider.GetListByNameAsync("ExampleStatuses");
if (list == null)
{
    sw.Stop();
    return Fail("E117", "ListItem - With Object", ExampleTier.Free, sw.ElapsedMilliseconds,
        "List 'ExampleStatuses' not found. Run E114 first.");
}

// Sync City scheme and create a city object
await redb.SyncSchemeAsync<CityProps>();
var cityObj = new RedbObject<CityProps>
{
    name = "Moscow",
    Props = new CityProps
    {
        Name = "Moscow",
        Population = 12_655_000,
        Region = "Central Federal District",
        IsCapital = true,
        Coordinates = [55.7558, 37.6173]
    }
};
var cityId = await redb.SaveAsync(cityObj);

// Create a new list item with object reference
var item = new RedbListItem(list, "Capital", "Capital city status", cityObj);

// Uncomment to see generated SQL:
// (Lists use direct ADO.NET, no ORM query)

var savedItem = await redb.ListProvider.SaveListItemAsync(item);

sw.Stop();
ListItemObjectReferenceIListProvider.SaveListItemAsyncRedbListItem.Object
MS 96ms(1)
MS Pro 126ms(1)
PG 94ms(1)
PG Pro 129ms(1)

Props - ListItem Field

Object with ListItem field in Props.
Shows how to store reference to list item in object properties.
Requires E114+E115 to run first.
var sw = Stopwatch.StartNew();

// Get existing list
var list = await redb.ListProvider.GetListByNameAsync("ExampleStatuses");
if (list == null)
{
    sw.Stop();
    return Fail("E118", "Props - ListItem Field", ExampleTier.Free, sw.ElapsedMilliseconds,
        "List 'ExampleStatuses' not found. Run E114 first.");
}

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

// Sync Person scheme
await redb.SyncSchemeAsync<PersonProps>();

// Create person with Status field (ListItem)
var person = new RedbObject<PersonProps>
{
    name = "John Doe",
    Props = new PersonProps
    {
        Name = "John Doe",
        Age = 30,
        Email = "john@example.com",
        Status = activeStatus  // Single ListItem field
    }
};

// Uncomment to see generated SQL:
// (Save uses COPY protocol for Pro)

var personId = await redb.SaveAsync(person);

// Load back to verify
redb.PropsCache.Clear();
var loaded = await redb.LoadAsync<PersonProps>(personId);

sw.Stop();

var statusValue = loaded?.Props?.Status?.Value ?? "N/A";
PropsListItemFieldRedbListItem
MS 96ms(1)
MS Pro 116ms(1)
PG 97ms(1)
PG Pro 129ms(1)

Props - List<ListItem>

Object with List of ListItems field in Props.
Shows how to store multiple list item references (e.g. roles, tags).
Requires E114+E115 to run first.
var sw = Stopwatch.StartNew();

// Get existing list
var list = await redb.ListProvider.GetListByNameAsync("ExampleStatuses");
if (list == null)
{
    sw.Stop();
    return Fail("E119", "Props - List<ListItem>", ExampleTier.Free, sw.ElapsedMilliseconds,
        "List 'ExampleStatuses' not found. Run E114 first.");
}

// Get list items
var items = await redb.ListProvider.GetListItemsAsync(list.Id);
if (items.Count < 2)
{
    sw.Stop();
    return Fail("E119", "Props - List<ListItem>", ExampleTier.Free, sw.ElapsedMilliseconds,
        "Need at least 2 items. Run E115 first.");
}

// Sync Person scheme
await redb.SyncSchemeAsync<PersonProps>();

// Create person with Roles field (List<ListItem>)
var person = new RedbObject<PersonProps>
{
    name = "Jane Smith",
    Props = new PersonProps
    {
        Name = "Jane Smith",
        Age = 28,
        Email = "jane@example.com",
        Roles = items.Take(3).ToList()  // Multiple ListItem references
    }
};

// Uncomment to see generated SQL:
// (Save uses COPY protocol for Pro)

var personId = await redb.SaveAsync(person);

// Load back to verify
redb.PropsCache.Clear();
var loaded = await redb.LoadAsync<PersonProps>(personId);

sw.Stop();

var rolesCount = loaded?.Props?.Roles?.Count ?? 0;
var rolesList = loaded?.Props?.Roles != null 
    ? string.Join(", ", loaded.Props.Roles.Select(r => r.Value))
    : "N/A";
PropsListItemArrayRolesList<RedbListItem>
MS 88ms(3)
MS Pro 105ms(3)
PG 101ms(3)
PG Pro 126ms(3)

ListItem - Where by Value

Query filtering by ListItem.Value property.
Shows how to filter objects by the Value of a ListItem field.
Requires E114-E118 to run first.
var sw = Stopwatch.StartNew();

// Query persons where Status.Value == "Active"
var query = redb.Query<PersonProps>()
    .Where(p => p.Status!.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("E120", "ListItem - Where by Value", ExampleTier.Free, sw.ElapsedMilliseconds, 0,
        ["No persons with Status='Active' found", "Run E118 first to create test data"]);
}

var firstName = results.FirstOrDefault()?.Props?.Name ?? "N/A";
ListItemWhereValueQueryIRedbQueryable.WhereRedbListItem.Value
MS 9ms(2)
MS Pro 57ms(1)
PG 9ms(1)
PG Pro 13ms(1)