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 parameters

  • Action: 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

Aspect
Query (Get Paged List)
Command (Insert/Update/Delete)

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

  1. Pagination Support: Built-in pagination with FlexiPagedList<T>

  2. AutoMapper Integration: Automatic entity-to-DTO mapping

  3. Query Building: Flexible query construction with filtering

  4. Performance: Optimized for data retrieval

  5. 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)

  1. GET Request β†’ Controller receives request with query parameters

  2. Service Processing β†’ Business orchestration and query resolution

  3. Query Handler β†’ Database query building and execution

  4. AutoMapper β†’ Entity-to-DTO transformation

  5. Pagination β†’ Apply pagination logic

  6. 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