For the complete documentation index, see llms.txt. This page is also available as Markdown.

Query Patterns

How-to · Applies to Darker V4

Query Pattern Introduction

This guide presents common query patterns you'll encounter when building real-world applications with Darker. While Queries and Query Objects covers the fundamentals of query design, and Implementing a Query Handler covers basic handler implementation, these pages focus on practical patterns for complex scenarios including pagination, projections, aggregations, and Entity Framework Core integration.

These patterns address real challenges like handling large data sets, optimizing query performance, working with related data, and implementing caching strategies. Each pattern includes complete, working examples that you can adapt to your specific needs.

Performance Best Practices

Pattern: Select Only What You Need

Always project to DTOs rather than loading full entities:

// ✅ Good: Select only needed fields
.Select(o => new OrderDto
{
    Id = o.Id,
    OrderDate = o.OrderDate,
    CustomerName = o.Customer.Name
})

// ❌ Bad: Load entire entity
.Select(o => o)  // or .ToList() directly

Pattern: Avoid N+1 Queries

N+1 problem: Loading a collection, then querying related data for each item.

Pattern: Use Async All the Way

Always use async methods for I/O operations:

Real-World Example: Product Catalog Query

Here's a complete, production-ready example combining multiple patterns:

Usage in controller:

Best Practices Summary

  1. Use pagination for any query that could return more than 100 items

  2. Project to DTOs using Select() - don't return domain entities

  3. Always use AsNoTracking() for read-only queries

  4. Use Include() wisely to avoid N+1 queries, but prefer projection when possible

  5. Cache appropriately - small, static lookup data is a good candidate

  6. Handle nulls explicitly - use nullable reference types (CustomerDto?)

  7. Use CancellationToken - pass it through to all async operations

  8. Validate query parameters in the query constructor

  9. Use compiled queries for hot-path queries

  10. Consider read replicas for scaling read-heavy workloads

Query Pattern Common Pitfalls

  1. Loading entire collections without pagination - Always paginate large result sets

  2. Forgetting AsNoTracking() - Wastes memory and CPU for read-only queries

  3. N+1 query problems - Use Include() or projections to avoid multiple round trips

  4. Over-fetching data - Select only the fields you need

  5. Under-fetching (multiple queries) - Use joins/includes to get related data in one query

  6. Not using CancellationToken - Prevents graceful cancellation of long-running queries

  7. Returning domain entities - Always project to DTOs for the query side

  8. Caching too aggressively - Consider staleness tolerance and cache invalidation

  9. Not optimizing database indexes - Ensure indexes exist for filter/sort columns

  10. Ignoring query performance - Monitor slow queries and optimize hot paths

Further Reading

Last updated

Was this helpful?