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; }
}
Array Contains + Conditions
Query employees combining array Contains with other conditions (Pro). Find senior C# developers over 30.
var sw = Stopwatch.StartNew();
// Pro: Combine array Contains with other conditions
var query = redb.Query<EmployeeProps>()
.Where(e => e.Skills!.Contains("C#") && e.Age >= 30 && e.Salary > 70000m)
.Take(100);
// Uncomment to see generated SQL:
// var sql = await query.ToSqlStringAsync();
// Console.WriteLine(sql);
var result = await query.ToListAsync();
sw.Stop();
ArrayContainsANDPro
MS1676ms(100)
MS Pro128ms(100)
PG1088ms(100)
PG Pro264ms(100)
Dict ContainsKey - Phone Directory
Query employees using Dictionary.ContainsKey. Find employees who have a desk phone.
var sw = Stopwatch.StartNew();
// Pro: Query dictionary with ContainsKey
var query = redb.Query<EmployeeProps>()
.Where(e => e.PhoneDirectory!.ContainsKey("desk"))
.Take(100);
// Uncomment to see generated SQL:
// var sql = await query.ToSqlStringAsync();
// Console.WriteLine(sql);
var result = await query.ToListAsync();
sw.Stop();
DictionaryContainsKeyPro
MS1544ms(100)
MS Pro86ms(100)
PG930ms(100)
PG Pro84ms(100)
Dict Indexer - Bonus by Year
Query employees using Dictionary indexer. Find employees with bonus over 6000 in 2023.
var sw = Stopwatch.StartNew();
// Pro: Query dictionary with indexer
var query = redb.Query<EmployeeProps>()
.Where(e => e.BonusByYear![2023] > 6000m)
.Take(100);
// Uncomment to see generated SQL:
//var sql = await query.ToSqlStringAsync();
//Console.WriteLine(sql);
var result = await query.ToListAsync();
sw.Stop();
DictionaryIndexerPro
MS1679ms(100)
MS Pro74ms(100)
PG1135ms(100)
PG Pro79ms(100)
Dict - Nested Class Property
Query employees using Dict indexer with nested class (Pro). Find employees whose HQ office is in specific city.
var sw = Stopwatch.StartNew();
// Pro: Dictionary<string, Address> with nested property access
var query = redb.Query<EmployeeProps>()
.Where(e => e.OfficeLocations!["HQ"].City == "New York")
.Take(100);
// Uncomment to see generated SQL:
// var sql = await query.ToSqlStringAsync();
// Console.WriteLine(sql);
var result = await query.ToListAsync();
sw.Stop();
DictionaryNestedClassPro
MS1706ms(100)
MS Pro164ms(100)
PG681ms(100)
PG Pro127ms(100)
Dict - Tuple Key
Query employees using Dict with tuple key (Pro). Find employees with specific performance review.
var sw = Stopwatch.StartNew();
// Pro: Dictionary<(int Year, string Quarter), string> with tuple key
// Tuple key must be in a variable for Expression Tree to work
var reviewKey = (Year: 2024, Quarter: "Q1");
var query = redb.Query<EmployeeProps>()
.Where(e => e.PerformanceReviews![reviewKey] == "Excellent")
.Take(100);
// Uncomment to see generated SQL:
// var sql = await query.ToSqlStringAsync();
// Console.WriteLine(sql);
var result = await query.ToListAsync();
sw.Stop();
DictionaryTupleKeyPro
MS1637ms(100)
MS Pro104ms(100)
PG667ms(100)
PG Pro104ms(100)
CountAsync - Total and Filtered
Count employees using CountAsync. Get total count and filtered count.
var sw = Stopwatch.StartNew();
// Total count
var totalCount = await redb.Query<EmployeeProps>().CountAsync();
// Filtered count
var managersCount = await redb.Query<EmployeeProps>()
.Where(e => e.Position == "Manager")
.CountAsync();
sw.Stop();
CountAggregate
MS15ms(5603)
MS Pro20ms(5086)
PG21ms(13769)
PG Pro45ms(13977)
AnyAsync - Check Existence
Check if any employees exist using AnyAsync(). Returns true if at least one record exists.
var sw = Stopwatch.StartNew();
// Check if any employees exist (no predicate)
var query = redb.Query<EmployeeProps>();
// Uncomment to see generated SQL:
// var sql = await query.ToSqlStringAsync();
// Console.WriteLine(sql);
var anyExist = await query.AnyAsync();
sw.Stop();
AnyExistsIRedbQueryable.AnyAsync
MS4ms(1)
MS Pro3ms(1)
PG4ms(1)
PG Pro4ms(1)
AnyAsync - With Predicate
Check if any employees match a condition using AnyAsync(predicate). More efficient than Where().AnyAsync() - stops at first match.
var sw = Stopwatch.StartNew();
// Check if any high earners exist (salary > 100k)
var query = redb.Query<EmployeeProps>();
// Uncomment to see generated SQL:
// var sql = await query.ToSqlStringAsync();
// Console.WriteLine(sql);
var anyHighEarners = await query.AnyAsync(e => e.Salary > 100_000m);
sw.Stop();
AnyPredicateFilterIRedbQueryable.AnyAsync
MS6ms(1)
MS Pro44ms(1)
PG10ms(1)
PG Pro32ms(1)
AllAsync - Check All Match
Check if ALL employees match a condition using AllAsync(predicate). Returns true only if every record satisfies the predicate.
var sw = Stopwatch.StartNew();
// Check if all employees have non-negative salary
var allNonNegativeSalary = await redb.Query<EmployeeProps>()
.AllAsync(e => e.Salary >= 0);
// Check if all high earners (>100k) are over 25 years old
var allHighEarnersOver25 = await redb.Query<EmployeeProps>()
.Where(e => e.Salary > 100000m)
.AllAsync(e => e.Age > 25);
// Negative check: are ALL employees millionaires? (expect false)
var allMillionaires = await redb.Query<EmployeeProps>()
.AllAsync(e => e.Salary > 1_000_000m);
sw.Stop();
// Count passed validations
var checks = new[] { allNonNegativeSalary, allHighEarnersOver25 };
var passedCount = checks.Count(c => c);
AllPredicateValidationIRedbQueryable.AllAsync
MS41ms(1)
MS Pro95ms(1)
PG65ms(1)
PG Pro138ms(1)
WhereIn - Filter by List
Filter employees by a list of values using WhereIn. Equivalent to SQL IN clause - much faster than multiple OR conditions.