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; }
}
Where - Arithmetic Multiply
Demonstrates arithmetic multiplication in Where clause. Calculates annual salary (monthly * 12) and filters employees earning over 1M per year. Pro feature: server-side arithmetic expressions.
var sw = Stopwatch.StartNew();
// Find employees with annual salary > 1,000,000
// Server-side: Salary * 12 > 1000000
var query = redb.Query<EmployeeProps>()
.Where(e => e.Salary * 12 > 1_000_000m)
.Take(100);
// Uncomment to see generated SQL:
// var sql = await query.ToSqlStringAsync();
// Console.WriteLine(sql);
var highEarners = await query.ToListAsync();
var totalCount = await redb.Query<EmployeeProps>()
.Where(e => e.Salary * 12 > 1_000_000m)
.CountAsync();
sw.Stop();
var first = highEarners.FirstOrDefault();
var annualSalary = first?.Props.Salary * 12 ?? 0;
ArithmeticMultiplyExpressionIRedbQueryable.Where
MS Pro150ms(2008)
PG Pro84ms(5573)
Where - Arithmetic Add Fields
Demonstrates arithmetic operations combining multiple fields in Where clause. Creates a "scoring" formula using Age and Salary to find senior valuable employees. Pro feature: server-side arithmetic with multiple Props fields.
var sw = Stopwatch.StartNew();
// Combined scoring: Age * 1000 + Salary > 120000
// Example: Age 40, Salary 85000 -> 40*1000 + 85000 = 125000 > 120000 ✓
var query = redb.Query<EmployeeProps>()
.Where(e => e.Age * 1000 + e.Salary > 120_000m)
.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 * 1000 + e.Salary > 120_000m)
.CountAsync();
sw.Stop();
var first = results.FirstOrDefault();
var score = first != null ? first.Props.Age * 1000 + (int)first.Props.Salary : 0;
ArithmeticAddMultiFieldIRedbQueryable.Where
MS Pro195ms(3185)
PG Pro110ms(8842)
Where - String ToLower
Demonstrates case-insensitive string search using ToLower() in Where clause. Finds employees whose last name contains "s" regardless of case (Smith, Jones, etc.). Pro feature: server-side LOWER() function.
Demonstrates Trim() function in Where clause to filter out empty or whitespace-only values. Finds employees with meaningful first names (not empty after trimming). Pro feature: server-side TRIM() function.
Demonstrates chaining multiple string functions in Where clause. Finds employees in departments with long uppercase names. Pro feature: server-side chained UPPER() + LENGTH() functions.
Demonstrates Math.Abs() in Where clause for range filtering around a target value. Finds employees aged 30-40 (within 5 years of 35). Pro feature: server-side ABS() function.
var sw = Stopwatch.StartNew();
// Find employees aged 30-40 (within 5 years of 35)
// |Age - 35| <= 5 means Age is between 30 and 40
var query = redb.Query<EmployeeProps>()
.Where(e => Math.Abs(e.Age - 35) <= 5)
.Take(100);
// Uncomment to see generated SQL (contains ABS):
// var sql = await query.ToSqlStringAsync();
// Console.WriteLine(sql);
var results = await query.ToListAsync();
var totalCount = await redb.Query<EmployeeProps>()
.Where(e => Math.Abs(e.Age - 35) <= 5)
.CountAsync();
sw.Stop();
var ages = results.Take(5).Select(e => e.Props.Age);
var avgAge = results.Any() ? results.Average(e => e.Props.Age) : 0;
MathAbsRangeIRedbQueryable.WhereMath.Abs
MS Pro115ms(1225)
PG Pro87ms(3402)
WhereRedb - DateTime.Year
Demonstrates DateTime property extraction in WhereRedb clause. Finds objects created in the current year using DateCreate.Year. Pro feature: server-side EXTRACT(YEAR FROM date) function.
var sw = Stopwatch.StartNew();
var currentYear = DateTime.UtcNow.Year;
// Find employees created in the current year
// Uses base field DateCreate (not Props) via WhereRedb
var query = redb.Query<EmployeeProps>()
.WhereRedb(o => o.DateCreate.Year == currentYear)
.Take(100);
// Uncomment to see generated SQL (contains EXTRACT):
// var sql = await query.ToSqlStringAsync();
// Console.WriteLine(sql);
var results = await query.ToListAsync();
var totalCount = await redb.Query<EmployeeProps>()
.WhereRedb(o => o.DateCreate.Year == currentYear)
.CountAsync();
sw.Stop();
var dates = results.Take(3).Select(e => e.date_create.ToString("yyyy-MM-dd"));
Demonstrates parentheses for operation priority in Where clause. Calculates monthly salary (annual / 12) and filters employees earning over $7,000/month. Pro feature: server-side arithmetic with correct operator precedence.
var sw = Stopwatch.StartNew();
// Find employees with monthly salary > $7,000
// Parentheses ensure division happens first: (Salary / 12) > 7000
var query = redb.Query<EmployeeProps>()
.Where(e => (e.Salary / 12m) > 7000m)
.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.Salary / 12m) > 7000m)
.CountAsync();
sw.Stop();
var first = results.FirstOrDefault();
var monthly = first?.Props.Salary / 12m ?? 0;
ArithmeticParenthesesPriorityIRedbQueryable.Where
MS Pro125ms(2008)
PG Pro90ms(5573)
Where - Nested Math
Demonstrates nested Math functions with arithmetic in Where clause. Finds employees with salary close to $80,000 (within $10,000 range). Pro feature: server-side ABS() with arithmetic expression inside.
var sw = Stopwatch.StartNew();
// Find employees with salary in range $70,000 - $90,000
// |Salary - 80000| < 10000 means Salary is between 70k and 90k
var query = redb.Query<EmployeeProps>()
.Where(e => Math.Abs(e.Salary - 80000m) < 10000m)
.Take(100);
// Uncomment to see generated SQL (contains ABS with expression):
// var sql = await query.ToSqlStringAsync();
// Console.WriteLine(sql);
var results = await query.ToListAsync();
var totalCount = await redb.Query<EmployeeProps>()
.Where(e => Math.Abs(e.Salary - 80000m) < 10000m)
.CountAsync();
sw.Stop();
var salaries = results.Take(5).Select(e => $"${e.Props.Salary:N0}");
var avgSalary = results.Any() ? results.Average(e => e.Props.Salary) : 0;
MathNestedRangeIRedbQueryable.WhereMath.Abs
MS Pro134ms(2498)
PG Pro82ms(6931)
TreeQuery - Expressions
Demonstrates arithmetic expressions in TreeQuery Where clause. Finds tree nodes where 10% of budget exceeds $50,000. Pro feature: server-side arithmetic in tree queries.
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("E160", "TreeQuery - Expressions", ExampleTier.Pro, sw.ElapsedMilliseconds,
"No tree data found. Please run E089_TreeCreate first.");
}
// Find departments where 10% of budget > $50,000 (i.e., Budget > $500,000)
var query = redb.TreeQuery<DepartmentProps>(root.Id)
.Where(d => d.Budget * 0.1m > 50000m)
.Take(100);
// Uncomment to see generated SQL:
// var sql = await query.ToSqlStringAsync();
// Console.WriteLine(sql);
var results = await query.ToListAsync();
sw.Stop();
var first = results.FirstOrDefault();
var tenPercent = first?.Props.Budget * 0.1m ?? 0;