Skip to content

Query Caching Examples

This directory contains examples of how to implement cacheable queries using the ICacheableQuery interface.

Basic Usage

To make a query cacheable, implement the ICacheableQuery interface:

using System.Runtime.Serialization;
using System.Security.Claims;
using LBS.Anchor;
using LBS.Augment.Authentication;

[DataContract(Name = "MyQuery")]
public class MyQuery : ISearchQuery, ICacheableQuery, IRequiresUserContext
{
    public string QueryType => this.GetType().GetQueryTypeName();
    public ClaimsPrincipal? User => UserContext.Current;

    // Query properties
    public string? SearchTerm { get; set; }

    // Cache configuration
    public string CacheKey => $"my-query:{SearchTerm ?? "all"}:{User?.Identity?.IsAuthenticated ?? false}";
    public TimeSpan DefaultCacheDuration => TimeSpan.FromMinutes(10);
    public string[]? CacheTags => ["my-data"];

    // Optional: Dynamic cache configuration based on results
    public void ConfigureCaching(IEnumerable<object> results, int totalCount, IFusionCacheContext context)
    {
        // Adjust cache duration based on result characteristics
        context.Options.Duration = totalCount switch
        {
            0 => TimeSpan.FromMinutes(1),     // Empty results
            < 10 => TimeSpan.FromMinutes(15), // Small results
            _ => TimeSpan.FromHours(1)        // Large results
        };
    }
}

Dynamic Cache Duration Patterns

Based on Result Count

context.Options.Duration = totalCount switch
{
    0 => TimeSpan.FromMinutes(1),           // Empty - short cache
    < 10 => TimeSpan.FromMinutes(15),       // Small - medium cache
    < 100 => TimeSpan.FromMinutes(30),      // Medium - longer cache
    _ => TimeSpan.FromHours(1)              // Large - longest cache
};

Based on Data Freshness (inspired by NrlController)

// For live data
context.Options.Duration = dataStatus switch
{
    "Live" => TimeSpan.FromSeconds(5),      // Frequently changing
    "Recent" => TimeSpan.FromMinutes(1),    // Moderately changing
    "Historical" => TimeSpan.FromHours(1),  // Stable data
    _ => TimeSpan.FromMinutes(5)            // Default
};

Based on User Context

// Different cache durations for authenticated vs anonymous users
var isAuthenticated = User?.Identity?.IsAuthenticated ?? false;
context.Options.Duration = isAuthenticated
    ? TimeSpan.FromMinutes(15)  // Authenticated users get fresher data
    : TimeSpan.FromMinutes(30); // Anonymous users get longer cache

Cache Invalidation

Use cache tags for invalidation:

public string[]? CacheTags => ["players", "team-123"];

// Later, invalidate all player-related caches:
await fusionCache.RemoveByTagAsync("players");

Service Chain

The query execution follows this chain:

  1. SecurityQueryService - Validates user permissions
  2. CachedQueryService - Checks cache, returns cached results or executes query
  3. QueryService - Executes the actual query against the database

Only queries implementing ICacheableQuery will be cached. All others pass through unchanged.