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 β Response
Detailed 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/GetOrders
Input:
GetOrdersParams
from 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