# Get Paged List Example

## Overview

This document demonstrates the complete **Get Paged List flow** using the **GetShippingPagedList** 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. This returns a paginated list of entities with metadata for data grids and large datasets.

## Complete Flow Architecture

```
GET Request → Controller → Service → Query Handler → RESTClient → External System
                                                                    ↓
Response ← Controller ← Service ← Query Handler ← RESTClient ← External System
```

### **Detailed Flow Breakdown**

```
1. GET Request
   ↓
2. Controller (API Entry Point)
   ↓
3. Service Layer (Business Orchestration)
   ↓
4. Query Handler (RESTClient Integration)
   ├── Internal DTO → Request DTO Mapping
   ├── RESTClient Call to External System
   └── Response DTO → Internal DTO Mapping
   ↓
5. Response (Paged List with Metadata)
```

## Step-by-Step Implementation

### 1. **API Controller** - The Entry Point

**File**: `ShippingController_GetShippingPagedList.cs`

```csharp
[HttpGet()]
[Route("GetShippingPagedList")]
[ProducesResponseType(typeof(FlexiPagedList<GetShippingPagedListDto>), 200)]
public async Task<IActionResult> GetShippingPagedList([FromQuery]GetShippingPagedListParams parameters)
{
    return RunQueryPagedService<GetShippingPagedListParams, GetShippingPagedListDto>(
                parameters, _processShippingService.GetShippingPagedList);
}
```

**What Happens:**

* **HTTP Method**: `GET /api/Shipping/GetShippingPagedList`
* **Input**: `GetShippingPagedListParams` from query parameters
* **Action**: Calls the service layer to process the query
* **Response**: HTTP 200 OK with `FlexiPagedList<GetShippingPagedListDto>`

### 2. **Service Layer** - Business Orchestration

**File**: `ProcessShippingService_GetShippingPagedList.cs`

```csharp
public FlexiPagedList<GetShippingPagedListDto> GetShippingPagedList(GetShippingPagedListParams @params)
{
    return _flexHost.GetFlexiQuery<GetShippingPagedList>().AssignParameters(@params).Fetch();
}
```

**What Happens:**

* **Query Resolution**: Gets the FlexiQuery instance for GetShippingPagedList
* **Parameter Assignment**: Assigns query parameters to the query handler
* **Query Execution**: Calls the Fetch() method to execute the query
* **Result**: Returns paginated list of shipping with metadata

### 3. **Query Handler** - RESTClient Integration

**File**: `GetShippingPagedList.cs`

```csharp
public class GetShippingPagedList : FlexiQueryPagedListBridge<Shipping, GetShippingPagedListDto>
{
    protected readonly ILogger<GetShippingPagedList> _logger;
    protected GetShippingPagedListParams _params;
    protected readonly ShippingRESTClient _restClient;

    public GetShippingPagedList(ILogger<GetShippingPagedList> logger, ShippingRESTClient restClient)
    {
        _logger = logger;
        _restClient = restClient;
    }

    public virtual GetShippingPagedList AssignParameters(GetShippingPagedListParams @params)
    {
        _params = @params;
        return this;
    }

    public override FlexiPagedList<GetShippingPagedListDto> Fetch()
    {
        try
        {
            // Convert internal parameters to Request DTO
            GetShippingPagedListRequestDto requestParams = new GetShippingPagedListRequestDto
            {
                PageNumber = _params.PageNumber,
                PageSize = _params.PageSize,
                SearchTerm = _params.SearchTerm,
                OrderId = _params.OrderId,
                Status = _params.Status?.ToString(),
                FromDate = _params.FromDate,
                ToDate = _params.ToDate,
                SortBy = _params.SortBy,
                SortDirection = _params.SortDirection
            };

            // Call external REST service
            var response = _restClient.GetShippingPagedList(requestParams).Result;

            if (response.IsSuccessStatusCode)
            {
                var responseContent = response.Content.ReadAsStringAsync().Result;
                var responseDto = JsonConvert.DeserializeObject<GetShippingPagedListResponseDto>(responseContent);
                
                // Convert Response DTO to Internal DTO
                var items = responseDto.Items?.Select(x => new GetShippingPagedListDto
                {
                    Id = x.Id,
                    OrderId = x.OrderId,
                    ShippingAddress = x.ShippingAddress,
                    TrackingNumber = x.TrackingNumber,
                    Status = ParseShippingStatus(x.Status),
                    StatusDescription = x.StatusDescription,
                    TotalWeight = x.TotalWeight,
                    CreatedDate = x.CreatedDate,
                    CreatedBy = x.CreatedBy,
                    IsActive = x.IsActive
                }).ToList() ?? new List<GetShippingPagedListDto>();

                // Create paginated result
                var result = new FlexiPagedList<GetShippingPagedListDto>
                {
                    Items = items,
                    TotalCount = responseDto.TotalCount,
                    PageNumber = responseDto.PageNumber,
                    PageSize = responseDto.PageSize,
                    TotalPages = responseDto.TotalPages,
                    HasPreviousPage = responseDto.HasPreviousPage,
                    HasNextPage = responseDto.HasNextPage
                };

                _logger.LogDebug("Shipping paged list retrieved successfully. Count: {Count}, Page: {PageNumber}", 
                    result.TotalCount, result.PageNumber);
                return result;
            }
            else
            {
                _logger.LogWarning("Failed to retrieve shipping paged list. Status: {StatusCode}", response.StatusCode);
                return new FlexiPagedList<GetShippingPagedListDto>
                {
                    Items = new List<GetShippingPagedListDto>(),
                    TotalCount = 0,
                    PageNumber = _params.PageNumber,
                    PageSize = _params.PageSize,
                    TotalPages = 0,
                    HasPreviousPage = false,
                    HasNextPage = false
                };
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error retrieving shipping paged list");
            return new FlexiPagedList<GetShippingPagedListDto>
            {
                Items = new List<GetShippingPagedListDto>(),
                TotalCount = 0,
                PageNumber = _params.PageNumber,
                PageSize = _params.PageSize,
                TotalPages = 0,
                HasPreviousPage = false,
                HasNextPage = false
            };
        }
    }

    private ShippingStatus ParseShippingStatus(string status)
    {
        return status?.ToLower() switch
        {
            "created" => ShippingStatus.Created,
            "in_transit" => ShippingStatus.InTransit,
            "delivered" => ShippingStatus.Delivered,
            "cancelled" => ShippingStatus.Cancelled,
            _ => ShippingStatus.Unknown
        };
    }
}
```

**What Happens:**

* **Parameter Assignment**: Stores query parameters for use in RESTClient calls
* **Request Mapping**: Converts internal parameters to Request DTO
* **RESTClient Call**: Calls external shipping service via RESTClient
* **Response Mapping**: Converts Response DTO to Internal DTO with pagination
* **Error Handling**: Handles success/failure responses from external system
* **Data Transformation**: Applies business logic during mapping

### 4. **Query Parameters** - Input DTO

**File**: `GetShippingPagedListParams.cs`

```csharp
public class GetShippingPagedListParams : DtoBridge
{
    // Pagination parameters
    public int PageNumber { get; set; } = 1;
    public int PageSize { get; set; } = 10;
    
    // Filtering parameters
    public string SearchTerm { get; set; }
    public string OrderId { get; set; }
    public ShippingStatus? Status { get; set; }
    public DateTime? FromDate { get; set; }
    public DateTime? ToDate { get; set; }
    
    // Sorting parameters
    public string SortBy { get; set; } = "CreatedDate";
    public string SortDirection { get; set; } = "desc";
}
```

**What Happens:**

* **Pagination**: PageNumber and PageSize for pagination control
* **Filtering**: Multiple filter options for data refinement
* **Sorting**: SortBy and SortDirection for data ordering
* **Query Parameters**: Automatically bound from URL query string

### 5. **Output DTO** - Data Transfer Object

**File**: `GetShippingPagedListDto.cs`

```csharp
public partial class GetShippingPagedListDto : DtoBridge 
{
    public string Id { get; set; }
    public string OrderId { get; set; }
    public string ShippingAddress { get; set; }
    public string TrackingNumber { get; set; }
    public ShippingStatus Status { get; set; }
    public string StatusDescription { get; set; }
    public decimal TotalWeight { get; set; }
    public DateTime CreatedDate { get; set; }
    public string CreatedBy { get; set; }
    public bool IsActive { get; set; }
}
```

**What Happens:**

* **Grid Data**: Contains fields suitable for data grid display
* **Essential Fields**: Includes key information for list views
* **Performance**: Optimized for large dataset display

### 6. **AutoMapper Configuration** - Data Transformation

**File**: `GetShippingPagedListMapperConfiguration.cs`

```csharp
public partial class GetShippingPagedListMapperConfiguration : FlexMapperProfile
{
    public GetShippingPagedListMapperConfiguration() : base()
    {
        CreateMap<Shipping, GetShippingPagedListDto>()
            .ForMember(d => d.StatusDescription, opt => opt.MapFrom(s => s.Status.ToString()))
            .ForMember(d => d.IsActive, opt => opt.MapFrom(s => !s.IsSoftDeleted));
    }
}
```

**What Happens:**

* **Entity to DTO Mapping**: Maps domain entities to DTOs
* **Custom Mappings**: Handles complex property transformations
* **Grid Optimization**: Maps fields optimized for data grid display

## Key Differences from Get List

### **Get Paged List vs Get List Characteristics**

| Aspect                | Get Paged List                    | Get List                       |
| --------------------- | --------------------------------- | ------------------------------ |
| **Return Type**       | `FlexiPagedList<T>`               | `IEnumerable<T>`               |
| **Pagination**        | ✅ Built-in pagination             | ❌ No pagination                |
| **Use Case**          | Data grids/tables                 | Lookup/Dropdown                |
| **Performance**       | Optimized for large datasets      | Fast for small datasets        |
| **Memory Usage**      | Higher (includes pagination info) | Lower (no pagination metadata) |
| **Controller Method** | `RunQueryPagedService`            | `RunQueryListService`          |
| **Query Base**        | `FlexiQueryPagedListBridge`       | `FlexiQueryEnumerableBridge`   |

### **Get Paged List-Specific Features**

1. **Pagination**: Built-in pagination with PageNumber and PageSize
2. **Metadata**: Includes total count, page count, and pagination info
3. **Large Datasets**: Optimized for handling large amounts of data
4. **Data Grids**: Perfect for admin interfaces and data tables
5. **Performance**: Efficient memory usage for large datasets

### **Common Use Cases**

* **Data Grids**: Populate data tables with pagination
* **Admin Interfaces**: Large dataset management
* **Reporting**: Paginated report data
* **Search Results**: Paginated search results
* **Audit Logs**: Large audit trail displays

## 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 to results
6. **Response** → HTTP 200 OK with paginated list and metadata

### **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**

```csharp
protected override IQueryable<T> Build<T>()
{
    _repoFactory.Init(_params);
    IQueryable<T> query = _repoFactory.GetRepo().FindAll<T>();
    
    // Add filtering logic here
    if (!string.IsNullOrEmpty(_params.SearchTerm))
    {
        query = query.Where(s => s.ShippingAddress.Contains(_params.SearchTerm) || 
                                s.TrackingNumber.Contains(_params.SearchTerm));
    }
    
    if (!string.IsNullOrEmpty(_params.OrderId))
    {
        query = query.Where(s => s.OrderId == _params.OrderId);
    }
    
    if (_params.Status.HasValue)
    {
        query = query.Where(s => s.Status == _params.Status.Value);
    }
    
    return query;
}
```

### **Advanced Query Building with Sorting**

```csharp
protected override IQueryable<T> Build<T>()
{
    _repoFactory.Init(_params);
    IQueryable<T> query = _repoFactory.GetRepo().FindAll<T>();
    
    // Exclude soft deleted items
    query = query.Where(s => !s.IsSoftDeleted);
    
    // Search functionality
    if (!string.IsNullOrEmpty(_params.SearchTerm))
    {
        var searchTerm = _params.SearchTerm.ToLower();
        query = query.Where(s => s.ShippingAddress.ToLower().Contains(searchTerm) || 
                                s.TrackingNumber.ToLower().Contains(searchTerm) ||
                                s.OrderId.ToLower().Contains(searchTerm));
    }
    
    // Order ID filtering
    if (!string.IsNullOrEmpty(_params.OrderId))
    {
        query = query.Where(s => s.OrderId == _params.OrderId);
    }
    
    // Status filtering
    if (_params.Status.HasValue)
    {
        query = query.Where(s => s.Status == _params.Status.Value);
    }
    
    // Date range filtering
    if (_params.FromDate.HasValue)
    {
        query = query.Where(s => s.CreatedDate >= _params.FromDate.Value);
    }
    
    if (_params.ToDate.HasValue)
    {
        query = query.Where(s => s.CreatedDate <= _params.ToDate.Value);
    }
    
    // Dynamic sorting
    switch (_params.SortBy?.ToLower())
    {
        case "createddate":
            query = _params.SortDirection?.ToLower() == "asc" 
                ? query.OrderBy(s => s.CreatedDate)
                : query.OrderByDescending(s => s.CreatedDate);
            break;
        case "status":
            query = _params.SortDirection?.ToLower() == "asc" 
                ? query.OrderBy(s => s.Status)
                : query.OrderByDescending(s => s.Status);
            break;
        case "trackingnumber":
            query = _params.SortDirection?.ToLower() == "asc" 
                ? query.OrderBy(s => s.TrackingNumber)
                : query.OrderByDescending(s => s.TrackingNumber);
            break;
        default:
            query = query.OrderByDescending(s => s.CreatedDate);
            break;
    }
    
    return query;
}
```

## Pagination Metadata

### **FlexiPagedList Structure**

```csharp
public class FlexiPagedList<T>
{
    public IEnumerable<T> Items { get; set; }
    public int TotalCount { get; set; }
    public int PageNumber { get; set; }
    public int PageSize { get; set; }
    public int TotalPages { get; set; }
    public bool HasPreviousPage { get; set; }
    public bool HasNextPage { get; set; }
}
```

### **Frontend Integration Example**

```javascript
// Example frontend usage
const response = await fetch('/api/Shipping/GetShippingPagedList?pageNumber=1&pageSize=10&searchTerm=tracking');
const pagedData = await response.json();

console.log(`Total items: ${pagedData.totalCount}`);
console.log(`Page ${pagedData.pageNumber} of ${pagedData.totalPages}`);
console.log(`Items:`, pagedData.items);
```

## Performance Considerations

### **Optimization Strategies**

1. **Database Indexing**: Ensure proper indexes on filter and sort fields
2. **Selective Fields**: Only return necessary fields in DTO
3. **Query Optimization**: Use efficient WHERE clauses and sorting
4. **Page Size Limits**: Set reasonable maximum page sizes
5. **Caching**: Consider caching for frequently accessed data

### **When to Use Get Paged List vs Get List**

| Scenario                | Use Get Paged List | Use Get List |
| ----------------------- | ------------------ | ------------ |
| **Data Grids**          | ✅ Yes              | ❌ No         |
| **Large Datasets**      | ✅ Yes              | ❌ No         |
| **Admin Interfaces**    | ✅ Yes              | ❌ No         |
| **Reporting**           | ✅ Yes              | ❌ No         |
| **Dropdown Population** | ❌ No               | ✅ Yes        |
| **Lookup Tables**       | ❌ No               | ✅ Yes        |
| **Auto-complete**       | ❌ No               | ✅ Yes        |

## Error Handling

### **HTTP Status Codes**

* **200 OK**: Data retrieved successfully
* **400 Bad Request**: Invalid parameters (invalid page number, page size)
* **500 Internal Server Error**: Database or server error

### **Parameter Validation**

```csharp
[HttpGet()]
[Route("GetShippingPagedList")]
[ProducesResponseType(typeof(FlexiPagedList<GetShippingPagedListDto>), 200)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> GetShippingPagedList([FromQuery]GetShippingPagedListParams parameters)
{
    // Validate pagination parameters
    if (parameters.PageNumber < 1)
    {
        return BadRequest("Page number must be greater than 0");
    }
    
    if (parameters.PageSize < 1 || parameters.PageSize > 100)
    {
        return BadRequest("Page size must be between 1 and 100");
    }
    
    return RunQueryPagedService<GetShippingPagedListParams, GetShippingPagedListDto>(
                parameters, _processShippingService.GetShippingPagedList);
}
```

## Key Benefits

* **Performance**: Optimized for large datasets with pagination
* **Memory Efficiency**: Only loads required page of data
* **User Experience**: Smooth navigation through large datasets
* **Metadata**: Rich pagination information for frontend
* **Type Safety**: Strongly typed DTOs and parameters
* **AutoMapper**: Automatic entity-to-DTO mapping
* **No Side Effects**: Read-only operations
* **Testable**: Each component can be tested independently
* **Maintainable**: Clear separation of concerns

***

**This GetShippingPagedList example demonstrates how FlexBase enables clean, maintainable, and scalable paginated list operations optimized for data grids and large datasets!** 🚀


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.flexbase.in/solution-structure/getting-started/features/rest-services/get-paged-list-example.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
