Get Paged List Example
Overview
This document demonstrates the complete Get Paged List flow using the GetOrders feature from the EBusiness application. The flow starts with a GET request to the controller and uses Query projects instead of Handlers in the DomainHandler section for data retrieval.
Complete Flow Architecture
GET Request → Controller → Service → Query Handler → Database → ResponseDetailed Flow Breakdown
1. GET Request
↓
2. Controller (API Entry Point)
↓
3. Service Layer (Business Orchestration)
↓
4. Query Handler (Data Retrieval)
↓
5. Database (Data Query)
↓
6. AutoMapper (Data Transformation)
↓
7. Response (Paged Results)Step-by-Step Implementation
1. API Controller - The Entry Point
File: OrdersController_GetOrders.cs
[HttpGet()]
[Route("GetOrders")]
[ProducesResponseType(typeof(FlexiPagedList<GetOrdersDto>), 200)]
public async Task<IActionResult> GetOrders([FromQuery]GetOrdersParams parameters)
{
return RunQueryPagedService<GetOrdersParams, GetOrdersDto>(parameters, _processOrdersService.GetOrders);
}What Happens:
HTTP Method:
GET /api/Orders/GetOrdersInput:
GetOrdersParamsfrom query parametersAction: Calls the service layer to process the query
Response: HTTP 200 OK with
FlexiPagedList<GetOrdersDto>
2. Service Layer - Business Orchestration
File: ProcessOrdersService_GetOrders.cs
public FlexiPagedList<GetOrdersDto> GetOrders(GetOrdersParams @params)
{
return _flexHost.GetFlexiQuery<GetOrders>().AssignParameters(@params).Fetch();
}What Happens:
Query Resolution: Gets the FlexiQuery instance for GetOrders
Parameter Assignment: Assigns query parameters to the query handler
Query Execution: Calls the Fetch() method to execute the query
Result: Returns paged list of orders
3. Query Handler - Data Retrieval
File: GetOrders.cs
public class GetOrders : FlexiQueryPagedListBridge<Order, GetOrdersParams, GetOrdersDto, FlexAppContextBridge>
{
protected readonly ILogger<GetOrders> _logger;
protected GetOrdersParams _params;
protected readonly RepoFactory _repoFactory;
public GetOrders(ILogger<GetOrders> logger, RepoFactory repoFactory)
{
_logger = logger;
_repoFactory = repoFactory;
}
public virtual GetOrders AssignParameters(GetOrdersParams @params)
{
_params = @params;
return this;
}
public override FlexiPagedList<GetOrdersDto> Fetch()
{
var projection = Build<Order>().SelectTo<GetOrdersDto>().ToList();
var result = BuildPagedOutput(projection);
return result;
}
protected override IQueryable<T> Build<T>()
{
_repoFactory.Init(_params);
IQueryable<T> query = _repoFactory.GetRepo().FindAll<T>();
//Build Your Query With All Parameters Here
query = CreatePagedQuery<T>(query, _params.PageNumber, _params.PageSize);
return query;
}
}What Happens:
Parameter Assignment: Stores query parameters for use in query building
Query Building: Creates the database query with filtering and pagination
Data Projection: Uses AutoMapper to project to DTOs
Pagination: Applies pagination logic to the results
Result Building: Creates the paged output with metadata
4. Query Parameters - Input DTO
File: GetOrdersParams.cs
public class GetOrdersParams : PagedQueryParamsDtoBridge
{
// Inherits pagination properties from PagedQueryParamsDtoBridge:
// - PageNumber
// - PageSize
// - SortBy
// - SortDirection
// Add custom filtering parameters here
public string CustomerId { get; set; }
public DateTime? OrderDateFrom { get; set; }
public DateTime? OrderDateTo { get; set; }
public string OrderState { get; set; }
}What Happens:
Pagination Support: Inherits standard pagination properties
Custom Filters: Allows filtering by customer, date range, order state
Query Parameters: Automatically bound from URL query string
5. Output DTO - Data Transfer Object
File: GetOrdersDto.cs
public partial class GetOrdersDto : DtoBridge
{
public string CurrentOrderState { get; set; }
public DateTimeOffset OrderDate { get; set; }
public string CustomerId { get; set; }
public int TotalQty { get; set; }
public decimal TotalAmount { get; set; }
public ICollection<GetOrdersDto_OrderItem> OrderItems { get; set; }
}File: GetOrdersDto_OrderItem.cs
public partial class GetOrdersDto_OrderItem : DtoBridge
{
public string ProductId { get; set; }
public string ProductName { get; set; }
public int Qty { get; set; }
public decimal SellingPrice { get; set; }
public decimal Amount { get; set; }
}What Happens:
Data Structure: Defines the shape of returned data
Nested Objects: Includes related order items
Calculated Fields: Contains computed properties like Amount
6. AutoMapper Configuration - Data Transformation
File: GetOrdersMapperConfiguration.cs
public partial class GetOrdersMapperConfiguration : FlexMapperProfile
{
public GetOrdersMapperConfiguration() : base()
{
CreateMap<Order, GetOrdersDto>()
.ForMember(o => o.CurrentOrderState, opt => opt.MapFrom(o => o.OrderState.GetType().Name));
CreateMap<OrderItem, GetOrdersDto_OrderItem>()
.ForMember(o => o.ProductName, opt => opt.MapFrom(o => o.Product.Name))
.ForMember(o => o.Amount, opt => opt.MapFrom(o => o.SellingPrice * o.Qty));
}
}What Happens:
Entity to DTO Mapping: Maps domain entities to DTOs
Custom Mappings: Handles complex property transformations
Calculated Fields: Computes derived properties
Nested Mappings: Maps related entities to nested DTOs
Key Differences from Command Operations
Query vs Command Characteristics
Purpose
Data Retrieval
Data Modification
HTTP Method
GET
POST, PUT, DELETE
Handler Type
Query Handler
Command Handler
Return Type
FlexiPagedList<T>
CommandResult
Database Operation
SELECT
INSERT, UPDATE, DELETE
Events
❌ No events published
✅ Events published
PreBus
❌ No PreBus validation
✅ PreBus validation
State Changes
❌ No state changes
✅ State changes
Query-Specific Features
Pagination Support: Built-in pagination with
FlexiPagedList<T>AutoMapper Integration: Automatic entity-to-DTO mapping
Query Building: Flexible query construction with filtering
Performance: Optimized for data retrieval
No Side Effects: Read-only operations
Pagination Features
PageNumber: Current page number (1-based)
PageSize: Number of items per page
TotalCount: Total number of items across all pages
TotalPages: Total number of pages
HasNextPage: Whether there are more pages
HasPreviousPage: Whether there are previous pages
Flow Summary
Synchronous Flow (Data Retrieval)
GET Request → Controller receives request with query parameters
Service Processing → Business orchestration and query resolution
Query Handler → Database query building and execution
AutoMapper → Entity-to-DTO transformation
Pagination → Apply pagination logic
Response → HTTP 200 OK with paged results
No Asynchronous Flow
No Events: Query operations don't publish events
No Subscribers: No side effects or event processing
Immediate Response: Data is returned immediately
Query Building Patterns
Basic Query Building
protected override IQueryable<T> Build<T>()
{
_repoFactory.Init(_params);
IQueryable<T> query = _repoFactory.GetRepo().FindAll<T>();
// Add filtering logic here
if (!string.IsNullOrEmpty(_params.CustomerId))
{
query = query.Where(o => o.CustomerId == _params.CustomerId);
}
if (_params.OrderDateFrom.HasValue)
{
query = query.Where(o => o.OrderDate >= _params.OrderDateFrom.Value);
}
// Apply pagination
query = CreatePagedQuery<T>(query, _params.PageNumber, _params.PageSize);
return query;
}Advanced Query Building
protected override IQueryable<T> Build<T>()
{
_repoFactory.Init(_params);
IQueryable<T> query = _repoFactory.GetRepo().FindAll<T>();
// Complex filtering
query = query.Where(o => !o.IsSoftDeleted);
if (!string.IsNullOrEmpty(_params.CustomerId))
{
query = query.Where(o => o.CustomerId == _params.CustomerId);
}
// Date range filtering
if (_params.OrderDateFrom.HasValue && _params.OrderDateTo.HasValue)
{
query = query.Where(o => o.OrderDate >= _params.OrderDateFrom.Value &&
o.OrderDate <= _params.OrderDateTo.Value);
}
// State filtering
if (!string.IsNullOrEmpty(_params.OrderState))
{
query = query.Where(o => o.OrderState.GetType().Name == _params.OrderState);
}
// Sorting
if (!string.IsNullOrEmpty(_params.SortBy))
{
switch (_params.SortBy.ToLower())
{
case "orderdate":
query = _params.SortDirection == "desc"
? query.OrderByDescending(o => o.OrderDate)
: query.OrderBy(o => o.OrderDate);
break;
case "totalamount":
query = _params.SortDirection == "desc"
? query.OrderByDescending(o => o.TotalAmount)
: query.OrderBy(o => o.TotalAmount);
break;
}
}
// Apply pagination
query = CreatePagedQuery<T>(query, _params.PageNumber, _params.PageSize);
return query;
}Key Benefits
Performance: Optimized for data retrieval with pagination
Flexibility: Easy to add filtering and sorting
Type Safety: Strongly typed DTOs and parameters
AutoMapper: Automatic entity-to-DTO mapping
Pagination: Built-in pagination support
No Side Effects: Read-only operations
Testable: Each component can be tested independently
Maintainable: Clear separation of concerns
This GetOrders example demonstrates how FlexBase enables clean, maintainable, and scalable query operations with built-in pagination, filtering, and data transformation capabilities! 🚀
Last updated