Data Model - EmployeePropsClick 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; }
}
Delete - Single Object
Demonstrates deleting a single object by ID. Creates a temporary object, then deletes it.
var sw = Stopwatch.StartNew();
// Create temporary objects to delete
var scheme = await redb.EnsureSchemeFromTypeAsync<EmployeeProps>();
var batchId = DateTime.UtcNow.Ticks;
var tempObjects = new List<RedbObject<EmployeeProps>>();
for (int i = 0; i < 5; i++)
{
tempObjects.Add(new RedbObject<EmployeeProps>
{
name = $"BatchDelete_{batchId}_{i}",
scheme_id = scheme.Id,
Props = new EmployeeProps
{
FirstName = $"Temp{i}",
LastName = "Employee",
Age = 20 + i,
Salary = 40000m + i * 1000,
Department = "Test"
}
});
}
// Save all
var ids = await redb.SaveAsync(tempObjects.Cast<Core.Models.Contracts.IRedbObject>());
// Verify count before delete
var countBefore = (await redb.LoadAsync(ids)).Count;
// Delete all by IDs
foreach (var id in ids)
{
await redb.DeleteAsync(id);
}
// Verify count after delete
var countAfter = (await redb.LoadAsync(ids)).Count;
sw.Stop();
DeleteBatchMultipleIRedbService.DeleteAsync
MS306ms(5)
MS Pro288ms(5)
PG530ms(5)
PG Pro537ms(5)
FirstOrDefaultAsync
Demonstrates FirstOrDefaultAsync to get a single object matching criteria. Returns the first match or null if none found.
var sw = Stopwatch.StartNew();
// Get first employee with salary > 80000
var highEarner = await redb.Query<EmployeeProps>()
.Where(e => e.Salary > 80000m)
.OrderByDescending(e => e.Salary)
.FirstOrDefaultAsync();
// Get first with impossible condition (should be null)
var notFound = await redb.Query<EmployeeProps>()
.Where(e => e.Salary > 10_000_000m)
.FirstOrDefaultAsync();
sw.Stop();
if (highEarner == null)
{
return Fail("E183", "FirstOrDefaultAsync", ExampleTier.Free, sw.ElapsedMilliseconds,
"No employees with salary > 80000 found.");
}
var sw = Stopwatch.StartNew();
// Combined conditions: Age > 30 AND Salary > 70000
var expHighEarnersCount = await redb.Query<EmployeeProps>()
.Where(e => e.Age > 30 && e.Salary > 70000m)
.CountAsync();
var expHighEarners = await redb.Query<EmployeeProps>()
.Where(e => e.Age > 30 && e.Salary > 70000m)
.Take(5)
.ToListAsync();
// OR conditions: Department == "IT" OR Department == "Engineering"
var techDeptCount = await redb.Query<EmployeeProps>()
.Where(e => e.Department == "IT" || e.Department == "Engineering")
.CountAsync();
sw.Stop();
var names = expHighEarners.Take(3).Select(e => $"{e.Props.FirstName} ({e.Props.Age}, ${e.Props.Salary:N0})");
WhereCombinedMultipleIRedbQueryable.Where
MS122ms(4913)
MS Pro167ms(4458)
PG183ms(12193)
PG Pro109ms(12375)
Object Reference - Load
Demonstrates loading objects with RedbObject references. EmployeeProps has CurrentProject field of type RedbObject<ProjectMetricsProps>. Shows how referenced objects are loaded.
SumAsync with Where filter applied before aggregation. Filter employees by department, then calculate total salary. Tests Pro filter handling in Aggregation.
var sw = Stopwatch.StartNew();
// Uncomment to see generated SQL:
//var sql = await redb.Query<EmployeeProps>()
// .Where(x => x.Department == "Engineering")
// .ToSqlStringAsync();
//Console.WriteLine(sql);
// Sum salaries only for Engineering department
var engineeringSalary = await redb.Query<EmployeeProps>()
.Where(x => x.Department == "Engineering")
.SumAsync(x => x.Salary);
// Compare with total (no filter)
var totalSalary = await redb.Query<EmployeeProps>()
.SumAsync(x => x.Salary);
sw.Stop();
Window function with Where filter applied before windowing. Filter employees by salary threshold, then apply ROW_NUMBER. Tests Pro filter handling in Window queries.
Multiple aggregations with Where filter applied before aggregation. Filter employees by position, then calculate Sum, Avg, Min, Max. Tests Pro filter handling in batch Aggregation.